detached 574f9a2

Merge pull request #181 from bnema/remove-security-hardening-regression-doc

docs: remove internal security regression matrix
commit
574f9a27cecec784666b4aa17d7edd5892fc444b
author
bnema · · 2026-04-29 03:20 UTC
committer
GitHub · · 2026-04-29 03:20 UTC
merge of
f49cffc + 83b28ca · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
1 file · +0 -222
D docs/security-hardening-regression-matrix.md +0 -222
@@ -1,222 +0,0 @@
1-# Security Hardening Regression Matrix
2-
3-This matrix lists the behaviors that should be tested while implementing the security-hardening fixes from the audit. It is intentionally focused on regressions: normal Gordon workflows must continue to work while exploit paths are blocked.
4-
5-## Registry uploads
6-
7-### Normal behavior to preserve
8-- Docker push of a small image succeeds.
9-- Docker push with multiple layers succeeds when every layer is below the configured cumulative blob limit.
10-- Chunked blob upload succeeds when the cumulative size remains below the new cumulative limit setting, tentatively named `max_blob_size` unless implementation chooses a clearer config name.
11-- A final `PUT` with a valid digest finalizes the blob and returns OCI-compatible headers.
12-- Existing `max_blob_chunk_size` behavior still rejects a single oversized chunk; this remains distinct from the cumulative per-blob/layer limit.
13-
14-### Security behavior to verify
15-- Repeated `PATCH` chunks cannot exceed the cumulative upload limit.
16-- `Content-Length` larger than the remaining allowed size is rejected before writing when possible.
17-- A rejected upload does not leave unbounded stale data on disk.
18-- Cancel/cleanup paths remove upload temp files and upload locks.
19-- Error response remains Docker Registry compatible (`413` / `SIZE_INVALID`).
20-
21-### Suggested tests
22-- Unit tests for filesystem blob append under and over cumulative size.
23-- Handler tests for `PATCH` and final `PUT` over limit.
24-- Integration/manual: push image with a large layer and confirm failure is clean.
25-
26-## Deploy errors and logs
27-
28-### Normal behavior to preserve
29-- Successful deploy response still includes status, domain, and container ID.
30-- Failed deploy still returns useful high-level error/cause/hint.
31-- Operators with the new logs permission can still retrieve logs through `/admin/logs`.
32-- CLI deploy displays helpful failure information without leaking raw secrets.
33-
34-### Security behavior to verify
35-- A token with only `admin:config:write` cannot receive raw container logs in `/admin/deploy` error responses.
36-- Logs returned through log endpoints are redacted for common secret patterns.
37-- `admin:status:read` no longer grants log read access.
38-- `admin:*:*` remains compatible and can access logs.
39-
40-### Suggested tests
41-- Handler tests for deploy error response with and without `logs:read`.
42-- Scope tests for `logs:read`, wildcard, and old `status:read` behavior.
43-- Redactor table tests for `PASSWORD=`, `TOKEN=`, `SECRET=`, `API_KEY=`, `DATABASE_URL=`, and simple JSON fields.
44-
45-## Admin scopes and compatibility
46-
47-### Normal behavior to preserve
48-- Existing `admin:*:*` tokens continue to work everywhere.
49-- Existing `routes`, `config`, `secrets`, and `status` scopes keep their intended behavior.
50-- Token exchange through `/auth/token` still works for admin scopes.
51-
52-### Security behavior to verify
53-- New sensitive resources such as `logs` and possibly `volumes` are parsed and enforced.
54-- Unknown or malformed scopes remain ignored/denied, not accidentally allowed.
55-
56-### Suggested tests
57-- Domain auth scope parsing tests.
58-- Admin middleware/handler tests for each sensitive endpoint.
59-
60-## Auto-route env-file extraction
61-
62-### Normal behavior to preserve
63-- Valid `gordon.env-file` imports default env values for a newly created auto-route.
64-- Existing env values still override image-provided defaults.
65-- Secret reference rejection remains intact.
66-- Auto-route without env-file remains unchanged.
67-
68-### Security behavior to verify
69-- Oversized env files are rejected before full memory read.
70-- Disallowed paths (`/proc`, `/sys`, `/dev`, `/run`, `/var/run`, `/`, traversal) are rejected.
71-- Failed env-file import does not prevent route/deploy behavior beyond the intended warning path unless explicitly designed.
72-
73-### Suggested tests
74-- Runtime extraction tests using a controlled reader larger than the limit.
75-- Auto-route usecase tests for allowed/disallowed paths.
76-- Tests confirming `${pass:...}` / `${sops:...}` refs remain rejected.
77-
78-## Domain canonicalization and proxy routing
79-
80-### Normal behavior to preserve
81-- Existing lowercase route domains continue to resolve.
82-- Registry domain still routes to registry.
83-- External routes still resolve and retain SSRF protections.
84-- Hostnames with expected public domains work through proxy.
85-
86-### Security behavior to verify
87-- `App.Example.com` and `app.example.com` map to the same canonical route.
88-- Duplicate case-variant routes cannot be created.
89-- Host with invalid port/trailing dot/case is handled consistently.
90-- HTTP-to-HTTPS redirect does not reflect arbitrary unconfigured Host values.
91-
92-### Suggested tests
93-- Config service tests for add/update/list canonical route domains.
94-- Auto-route tests for case variants.
95-- Proxy handler tests for Host normalization.
96-- Middleware tests for redirect target host validation.
97-
98-## Volumes
99-
100-### Normal behavior to preserve
101-- Listing volumes still shows Gordon-managed volumes.
102-- Dry-run prune still reports what would be removed.
103-- Actual prune still removes unused Gordon-managed volumes.
104-- In-use Gordon volumes are not removed.
105-
106-### Security behavior to verify
107-- Unused non-Gordon Docker volumes are not removed.
108-- Volumes without explicit Gordon ownership metadata, preferably `gordon.managed=true`, are ignored; prefix-only matching is unsafe except as a constrained legacy fallback with dedicated tests.
109-- Any new `volumes:read/write` scope is enforced correctly.
110-
111-### Suggested tests
112-- Volume service tests with mixed Gordon/non-Gordon, used/unused volumes.
113-- Admin handler tests for permissions.
114-- Manual: create an unrelated Docker volume, run Gordon prune dry-run/real, confirm it remains.
115-
116-## Backups
117-
118-### Normal behavior to preserve
119-- Manual backup completes and appears in list.
120-- Scheduled backup path format remains readable/listable.
121-- Backup detect still finds supported DB attachments.
122-- Existing backups can still be listed after filename format changes.
123-
124-### Security behavior to verify
125-- Two backups for same domain/db/schedule in the same second do not share tmp/final filenames.
126-- Concurrent backups do not truncate each other.
127-- Store uses unique tmp files and atomic rename.
128-- Path traversal protections remain intact.
129-
130-### Suggested tests
131-- Filesystem storage tests with identical timestamps.
132-- Concurrent store test with two readers and same domain/db/schedule.
133-- List tests for old and new filename formats if compatibility is needed.
134-
135-## Secrets and pass migration
136-
137-### Normal behavior to preserve
138-- `pass` backend still migrates existing env keys correctly.
139-- Attachment env migration still works.
140-- Unsafe backend still loads valid files under `dataDir/secrets` for development.
141-- Existing env file parsing remains compatible.
142-
143-### Security behavior to verify
144-- Unsafe backend rejects `../` and absolute `auth.token_secret` paths.
145-- Migration does not leave plaintext `.env.migrated` by default.
146-- If an explicit keep/quarantine option exists, files are stored with restrictive permissions and loud warnings.
147-
148-### Suggested tests
149-- `loadSecret` path traversal tests.
150-- Migration tests verifying plaintext source file removal/quarantine.
151-- Permission tests where practical (`0600` files, `0700` dirs).
152-
153-## Config snapshot
154-
155-### Normal behavior to preserve
156-- `/admin/config` still returns enough information for CLI/admin use.
157-- Routes and network isolation status remain visible to authorized callers.
158-
159-### Security behavior to verify
160-- `data_dir` is hidden by default or only available under a deliberately stronger detailed mode.
161-- External route targets are hidden/redacted by default or gated.
162-- `config:read` behavior remains documented.
163-
164-### Suggested tests
165-- Admin config response tests for default and detailed modes.
166-- CLI remote config tests if output shape changes.
167-
168-## External image registries
169-
170-### Normal behavior to preserve
171-- Images in the Gordon registry deploy normally.
172-- Explicitly allowlisted external registries deploy if configured.
173-- Attachments still deploy from allowed sources.
174-
175-### Security behavior to verify
176-- `localhost`, loopback, private IP, link-local, metadata IP, and DNS resolving to private ranges are rejected unless a deliberate unsafe override exists.
177-- Non-allowlisted external registries are rejected before Docker pull.
178-- Error messages do not leak sensitive network details.
179-
180-### Suggested tests
181-- Image reference validation table tests.
182-- Config tests for `allowed_registries`.
183-- Container service tests ensuring rejected images do not call `PullImage`.
184-
185-## Docker networks and runtime hardening
186-
187-### Normal behavior to preserve
188-- Default/compat profile keeps common apps and attachments working.
189-- Attachments remain reachable by service alias where intended.
190-- Network groups still work when configured.
191-
192-### Security behavior to verify
193-- `internal` network option is applied when configured.
194-- Strict profile applies readonly rootfs/user/caps as designed.
195-- `no-new-privileges:true` and cap dropping are preserved.
196-- Compat profile behavior is documented and tested.
197-
198-### Suggested tests
199-- Docker adapter config construction tests.
200-- Container service tests for network option propagation.
201-- Manual smoke: deploy app + postgres attachment in compat profile.
202-- Manual smoke: deploy simple read-only app in strict profile.
203-
204-## Install, Dockerfile, and supply-chain
205-
206-### Normal behavior to preserve
207-- `install.sh` installs the binary on Linux/macOS.
208-- GitHub composite action installs Gordon in CI.
209-- Dockerfile builds successfully.
210-
211-### Security behavior to verify
212-- Tar extraction only extracts `gordon`.
213-- Installed binary must be a regular file, not symlink/directory.
214-- Permissions are explicit (`0755`).
215-- Checksums/signatures are verified consistently.
216-- Gitleaks output is clean or only contains allowlisted examples.
217-
218-### Suggested tests
219-- Shellcheck/manual review for install script.
220-- Action script dry-run if practical.
221-- Docker build smoke after version alignment.
222-- Gitleaks on `git archive HEAD`, not local `.worktrees`.
@@ -1,222 +0,0 @@
1-# Security Hardening Regression Matrix
2-
3-This matrix lists the behaviors that should be tested while implementing the security-hardening fixes from the audit. It is intentionally focused on regressions: normal Gordon workflows must continue to work while exploit paths are blocked.
4-
5-## Registry uploads
6-
7-### Normal behavior to preserve
8-- Docker push of a small image succeeds.
9-- Docker push with multiple layers succeeds when every layer is below the configured cumulative blob limit.
10-- Chunked blob upload succeeds when the cumulative size remains below the new cumulative limit setting, tentatively named `max_blob_size` unless implementation chooses a clearer config name.
11-- A final `PUT` with a valid digest finalizes the blob and returns OCI-compatible headers.
12-- Existing `max_blob_chunk_size` behavior still rejects a single oversized chunk; this remains distinct from the cumulative per-blob/layer limit.
13-
14-### Security behavior to verify
15-- Repeated `PATCH` chunks cannot exceed the cumulative upload limit.
16-- `Content-Length` larger than the remaining allowed size is rejected before writing when possible.
17-- A rejected upload does not leave unbounded stale data on disk.
18-- Cancel/cleanup paths remove upload temp files and upload locks.
19-- Error response remains Docker Registry compatible (`413` / `SIZE_INVALID`).
20-
21-### Suggested tests
22-- Unit tests for filesystem blob append under and over cumulative size.
23-- Handler tests for `PATCH` and final `PUT` over limit.
24-- Integration/manual: push image with a large layer and confirm failure is clean.
25-
26-## Deploy errors and logs
27-
28-### Normal behavior to preserve
29-- Successful deploy response still includes status, domain, and container ID.
30-- Failed deploy still returns useful high-level error/cause/hint.
31-- Operators with the new logs permission can still retrieve logs through `/admin/logs`.
32-- CLI deploy displays helpful failure information without leaking raw secrets.
33-
34-### Security behavior to verify
35-- A token with only `admin:config:write` cannot receive raw container logs in `/admin/deploy` error responses.
36-- Logs returned through log endpoints are redacted for common secret patterns.
37-- `admin:status:read` no longer grants log read access.
38-- `admin:*:*` remains compatible and can access logs.
39-
40-### Suggested tests
41-- Handler tests for deploy error response with and without `logs:read`.
42-- Scope tests for `logs:read`, wildcard, and old `status:read` behavior.
43-- Redactor table tests for `PASSWORD=`, `TOKEN=`, `SECRET=`, `API_KEY=`, `DATABASE_URL=`, and simple JSON fields.
44-
45-## Admin scopes and compatibility
46-
47-### Normal behavior to preserve
48-- Existing `admin:*:*` tokens continue to work everywhere.
49-- Existing `routes`, `config`, `secrets`, and `status` scopes keep their intended behavior.
50-- Token exchange through `/auth/token` still works for admin scopes.
51-
52-### Security behavior to verify
53-- New sensitive resources such as `logs` and possibly `volumes` are parsed and enforced.
54-- Unknown or malformed scopes remain ignored/denied, not accidentally allowed.
55-
56-### Suggested tests
57-- Domain auth scope parsing tests.
58-- Admin middleware/handler tests for each sensitive endpoint.
59-
60-## Auto-route env-file extraction
61-
62-### Normal behavior to preserve
63-- Valid `gordon.env-file` imports default env values for a newly created auto-route.
64-- Existing env values still override image-provided defaults.
65-- Secret reference rejection remains intact.
66-- Auto-route without env-file remains unchanged.
67-
68-### Security behavior to verify
69-- Oversized env files are rejected before full memory read.
70-- Disallowed paths (`/proc`, `/sys`, `/dev`, `/run`, `/var/run`, `/`, traversal) are rejected.
71-- Failed env-file import does not prevent route/deploy behavior beyond the intended warning path unless explicitly designed.
72-
73-### Suggested tests
74-- Runtime extraction tests using a controlled reader larger than the limit.
75-- Auto-route usecase tests for allowed/disallowed paths.
76-- Tests confirming `${pass:...}` / `${sops:...}` refs remain rejected.
77-
78-## Domain canonicalization and proxy routing
79-
80-### Normal behavior to preserve
81-- Existing lowercase route domains continue to resolve.
82-- Registry domain still routes to registry.
83-- External routes still resolve and retain SSRF protections.
84-- Hostnames with expected public domains work through proxy.
85-
86-### Security behavior to verify
87-- `App.Example.com` and `app.example.com` map to the same canonical route.
88-- Duplicate case-variant routes cannot be created.
89-- Host with invalid port/trailing dot/case is handled consistently.
90-- HTTP-to-HTTPS redirect does not reflect arbitrary unconfigured Host values.
91-
92-### Suggested tests
93-- Config service tests for add/update/list canonical route domains.
94-- Auto-route tests for case variants.
95-- Proxy handler tests for Host normalization.
96-- Middleware tests for redirect target host validation.
97-
98-## Volumes
99-
100-### Normal behavior to preserve
101-- Listing volumes still shows Gordon-managed volumes.
102-- Dry-run prune still reports what would be removed.
103-- Actual prune still removes unused Gordon-managed volumes.
104-- In-use Gordon volumes are not removed.
105-
106-### Security behavior to verify
107-- Unused non-Gordon Docker volumes are not removed.
108-- Volumes without explicit Gordon ownership metadata, preferably `gordon.managed=true`, are ignored; prefix-only matching is unsafe except as a constrained legacy fallback with dedicated tests.
109-- Any new `volumes:read/write` scope is enforced correctly.
110-
111-### Suggested tests
112-- Volume service tests with mixed Gordon/non-Gordon, used/unused volumes.
113-- Admin handler tests for permissions.
114-- Manual: create an unrelated Docker volume, run Gordon prune dry-run/real, confirm it remains.
115-
116-## Backups
117-
118-### Normal behavior to preserve
119-- Manual backup completes and appears in list.
120-- Scheduled backup path format remains readable/listable.
121-- Backup detect still finds supported DB attachments.
122-- Existing backups can still be listed after filename format changes.
123-
124-### Security behavior to verify
125-- Two backups for same domain/db/schedule in the same second do not share tmp/final filenames.
126-- Concurrent backups do not truncate each other.
127-- Store uses unique tmp files and atomic rename.
128-- Path traversal protections remain intact.
129-
130-### Suggested tests
131-- Filesystem storage tests with identical timestamps.
132-- Concurrent store test with two readers and same domain/db/schedule.
133-- List tests for old and new filename formats if compatibility is needed.
134-
135-## Secrets and pass migration
136-
137-### Normal behavior to preserve
138-- `pass` backend still migrates existing env keys correctly.
139-- Attachment env migration still works.
140-- Unsafe backend still loads valid files under `dataDir/secrets` for development.
141-- Existing env file parsing remains compatible.
142-
143-### Security behavior to verify
144-- Unsafe backend rejects `../` and absolute `auth.token_secret` paths.
145-- Migration does not leave plaintext `.env.migrated` by default.
146-- If an explicit keep/quarantine option exists, files are stored with restrictive permissions and loud warnings.
147-
148-### Suggested tests
149-- `loadSecret` path traversal tests.
150-- Migration tests verifying plaintext source file removal/quarantine.
151-- Permission tests where practical (`0600` files, `0700` dirs).
152-
153-## Config snapshot
154-
155-### Normal behavior to preserve
156-- `/admin/config` still returns enough information for CLI/admin use.
157-- Routes and network isolation status remain visible to authorized callers.
158-
159-### Security behavior to verify
160-- `data_dir` is hidden by default or only available under a deliberately stronger detailed mode.
161-- External route targets are hidden/redacted by default or gated.
162-- `config:read` behavior remains documented.
163-
164-### Suggested tests
165-- Admin config response tests for default and detailed modes.
166-- CLI remote config tests if output shape changes.
167-
168-## External image registries
169-
170-### Normal behavior to preserve
171-- Images in the Gordon registry deploy normally.
172-- Explicitly allowlisted external registries deploy if configured.
173-- Attachments still deploy from allowed sources.
174-
175-### Security behavior to verify
176-- `localhost`, loopback, private IP, link-local, metadata IP, and DNS resolving to private ranges are rejected unless a deliberate unsafe override exists.
177-- Non-allowlisted external registries are rejected before Docker pull.
178-- Error messages do not leak sensitive network details.
179-
180-### Suggested tests
181-- Image reference validation table tests.
182-- Config tests for `allowed_registries`.
183-- Container service tests ensuring rejected images do not call `PullImage`.
184-
185-## Docker networks and runtime hardening
186-
187-### Normal behavior to preserve
188-- Default/compat profile keeps common apps and attachments working.
189-- Attachments remain reachable by service alias where intended.
190-- Network groups still work when configured.
191-
192-### Security behavior to verify
193-- `internal` network option is applied when configured.
194-- Strict profile applies readonly rootfs/user/caps as designed.
195-- `no-new-privileges:true` and cap dropping are preserved.
196-- Compat profile behavior is documented and tested.
197-
198-### Suggested tests
199-- Docker adapter config construction tests.
200-- Container service tests for network option propagation.
201-- Manual smoke: deploy app + postgres attachment in compat profile.
202-- Manual smoke: deploy simple read-only app in strict profile.
203-
204-## Install, Dockerfile, and supply-chain
205-
206-### Normal behavior to preserve
207-- `install.sh` installs the binary on Linux/macOS.
208-- GitHub composite action installs Gordon in CI.
209-- Dockerfile builds successfully.
210-
211-### Security behavior to verify
212-- Tar extraction only extracts `gordon`.
213-- Installed binary must be a regular file, not symlink/directory.
214-- Permissions are explicit (`0755`).
215-- Checksums/signatures are verified consistently.
216-- Gitleaks output is clean or only contains allowlisted examples.
217-
218-### Suggested tests
219-- Shellcheck/manual review for install script.
220-- Action script dry-run if practical.
221-- Docker build smoke after version alignment.
222-- Gitleaks on `git archive HEAD`, not local `.worktrees`.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close