Skip to content

Commit f243f30

Browse files
committed
Add security self-test gates
1 parent c8c6270 commit f243f30

16 files changed

Lines changed: 468 additions & 58 deletions

.github/codeql/codeql-config.yml

Lines changed: 0 additions & 9 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,16 @@ jobs:
3434
- name: Install security tools
3535
uses: taiki-e/install-action@v2
3636
with:
37-
tool: cargo-deny,cargo-audit
37+
tool: cargo-deny,cargo-audit,cargo-sbom
3838

39-
- name: Format
40-
run: cargo fmt --all --check
39+
- name: Run checks
40+
run: scripts/checks.sh
4141

42-
- name: Validate release metadata
43-
run: scripts/validate-release-metadata.sh
42+
- name: Local runtime smoke
43+
run: scripts/smoke_local.sh
4444

45-
- name: Check Markdown links
46-
run: perl scripts/check-doc-links.pl
45+
- name: Generate SBOM
46+
run: scripts/generate-sbom.sh
4747

48-
- name: Check
49-
run: cargo check
50-
51-
- name: Clippy
52-
run: cargo clippy --all-targets -- -D warnings
53-
54-
- name: Test
55-
run: cargo test
56-
57-
- name: Audit
58-
run: cargo audit
59-
60-
- name: Dependency policy
61-
run: cargo deny check
48+
- name: Verify reproducible release build
49+
run: scripts/reproducible_build_check.sh

.github/workflows/codeql.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: CodeQL
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
- cron: "31 3 * * 1"
10+
11+
permissions:
12+
actions: read
13+
contents: read
14+
security-events: write
15+
16+
jobs:
17+
analyze:
18+
name: Analyze Rust
19+
runs-on: ubuntu-latest
20+
timeout-minutes: 45
21+
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v6
25+
26+
- name: Initialize CodeQL
27+
uses: github/codeql-action/init@v4
28+
with:
29+
languages: rust
30+
build-mode: none
31+
32+
- name: Perform CodeQL Analysis
33+
uses: github/codeql-action/analyze@v4

Cargo.lock

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ documentation = "https://github.com/valkyoth/hashavatar-api"
1212
[dependencies]
1313
aws-config = { version = "1.8.16", default-features = false, features = ["rt-tokio"] }
1414
aws-sdk-s3 = { version = "1.131.0", default-features = false, features = ["rt-tokio", "sigv4a"] }
15-
hashavatar = "0.5.0"
15+
hashavatar = "0.6.0"
1616
image = { version = "0.25.10", default-features = false, features = ["png"] }
1717
axum = { version = "0.8.9", default-features = false, features = ["http1", "tokio", "query", "json"] }
1818
ipnet = { version = "2.12.0", default-features = false }

Cargo.toml.split-template

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ homepage = "https://github.com/valkyoth/hashavatar-api"
1010
documentation = "https://github.com/valkyoth/hashavatar-api"
1111

1212
[dependencies]
13-
hashavatar = "0.5.0"
13+
hashavatar = "0.6.0"
1414
axum = { version = "0.8.9", default-features = false, features = ["http1", "tokio", "query", "json"] }
1515
ipnet = { version = "2.12.0", default-features = false }
16-
lru = { version = "0.16.4", default-features = false }
16+
lru = { version = "0.18.0", default-features = false }
1717
serde = { version = "1.0.228", default-features = false, features = ["derive"] }
1818
serde_json = { version = "1.0.149", default-features = false, features = ["std"] }
1919
sha2 = { version = "0.11.0", default-features = false, features = ["alloc"] }

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Supported backgrounds:
3030
- `light`
3131
- `transparent`
3232

33-
Supported avatar families are provided by `hashavatar 0.5.0`, including `cat`, `dog`, `robot`, `fox`, `alien`, `monster`, `ghost`, `slime`, `bird`, `wizard`, `skull`, `paws`, `planet`, `rocket`, `mushroom`, `cactus`, `frog`, `panda`, `cupcake`, `pizza`, `icecream`, `octopus`, and `knight`.
33+
Supported avatar families are provided by `hashavatar 0.6.0`, including `cat`, `dog`, `robot`, `fox`, `alien`, `monster`, `ghost`, `slime`, `bird`, `wizard`, `skull`, `paws`, `planet`, `rocket`, `mushroom`, `cactus`, `frog`, `panda`, `cupcake`, `pizza`, `icecream`, `octopus`, and `knight`.
3434

3535
## Example URLs
3636

@@ -103,13 +103,14 @@ direct peer address matches this allowlist.
103103
Recommended local checks:
104104

105105
```bash
106-
cargo fmt --check
107-
cargo check
108-
cargo clippy --all-targets -- -D warnings
109-
cargo audit
110-
cargo deny check
106+
scripts/checks.sh
107+
scripts/smoke_local.sh
108+
scripts/stable_release_gate.sh
111109
```
112110

111+
Security controls and release evidence checks are documented in
112+
[`docs/SECURITY_CONTROLS.md`](docs/SECURITY_CONTROLS.md).
113+
113114
## Running On Your Own Server
114115

115116
For self-hosting on Hetzner with Podman, see:

SECURITY.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Security fixes are expected for the latest published `0.5.x` release.
88

99
Please report security issues privately through GitHub Security Advisories for:
1010

11-
`https://github.com/valkyoth/hashavatar/security/advisories/new`
11+
`https://github.com/valkyoth/hashavatar-api/security/advisories/new`
1212

1313
If GitHub advisories are unavailable, open a minimal public issue that asks for a private contact path without disclosing exploit details.
1414

@@ -25,7 +25,9 @@ Please include reproduction steps, affected versions, and any known mitigations.
2525

2626
## Security Checks
2727

28-
CI runs formatting, clippy, tests, `cargo deny check`, and `cargo audit`.
29-
GitHub CodeQL default setup should be enabled in repository security settings;
30-
keep only one active CodeQL configuration to avoid duplicate code-scanning
31-
uploads.
28+
CI runs formatting, release metadata validation, documentation link checks,
29+
security invariant checks, clippy, tests, `cargo deny check`, `cargo audit`, a
30+
local runtime smoke test, SBOM generation, reproducible release build checks,
31+
and the default CodeQL workflow.
32+
33+
See `docs/SECURITY_CONTROLS.md` for the service-specific control map.

docs/SECURITY_CONTROLS.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Security Controls
2+
3+
This document maps the API service controls to the main risks covered by the
4+
local test and release gates.
5+
6+
## Runtime Controls
7+
8+
| Risk | Control |
9+
| --- | --- |
10+
| Unbounded rate-limit state | The rate limiter uses bounded LRU storage and has a regression test for unique attacker keys. |
11+
| Forwarded-header spoofing | `X-Forwarded-For`, `X-Real-IP`, and `CF-Connecting-IP` are honored only when the direct peer is a configured trusted proxy. |
12+
| Verbose internal errors | Internal errors are logged with `tracing`; clients receive a generic static 500 body. |
13+
| Browser-side content confusion | Responses receive CSP, `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, and `Permissions-Policy` headers. |
14+
| Oversized avatar namespace or identity input | `hashavatar 0.6.0` validates namespace and identity byte lengths before rendering. |
15+
| Vulnerable or incompatible dependencies | `cargo audit` and `cargo deny check` run in the standard check script and CI. |
16+
17+
## Self-Testing
18+
19+
- `scripts/checks.sh` is the fast local gate for formatting, release metadata,
20+
documentation links, security invariants, clippy, tests, dependency policy,
21+
and RustSec advisories.
22+
- `scripts/smoke_local.sh` starts the service locally, checks `/healthz`,
23+
renders SVG and PNG avatars, verifies security headers, and checks oversized
24+
namespace rejection.
25+
- `scripts/generate-sbom.sh` emits SPDX and CycloneDX SBOMs under
26+
`target/release-evidence`.
27+
- `scripts/reproducible_build_check.sh` builds the release binary twice in
28+
separate target directories and compares the result.
29+
- `scripts/stable_release_gate.sh` runs the fast gate, local smoke, SBOM, and
30+
reproducibility checks; optional Podman smoke can be enabled with
31+
`HASHAVATAR_API_GATE_PODMAN=1`.
32+
33+
## Boundaries
34+
35+
The API does not authenticate callers, encrypt responses, or provide abuse
36+
protection beyond local rate limiting. Deployments should still use a trusted
37+
reverse proxy, TLS, request logging controls, and infrastructure-level rate
38+
limits appropriate for the environment.

scripts/checks.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,31 @@
11
#!/usr/bin/env sh
22
set -eu
33

4+
echo "checks: formatting"
45
cargo fmt --all --check
6+
7+
echo "checks: release metadata"
58
scripts/validate-release-metadata.sh
9+
10+
echo "checks: documentation links"
611
perl scripts/check-doc-links.pl
12+
13+
echo "checks: security invariants"
14+
scripts/validate-security-invariants.sh
15+
16+
echo "checks: cargo check"
717
cargo check
18+
19+
echo "checks: clippy"
820
cargo clippy --all-targets -- -D warnings
21+
22+
echo "checks: tests"
923
cargo test
24+
25+
echo "checks: dependency policy"
1026
cargo deny check
27+
28+
echo "checks: RustSec advisories"
1129
cargo audit
30+
31+
echo "checks: ok"

0 commit comments

Comments
 (0)