mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 16:34:00 +01:00
feat(sealed): sealed-output guard over every published commit, in the pre-push hook and gstack-pregate sealed
A repo with a sealed key in .gstack/pregate.json (base branch union the pushed commit, so a push can tighten but never relax) refuses publishing sealed paths, transcripts, quoted answers, seeds or local home paths to a public or unknown destination (SEALED_OUTPUT_REFUSED); private warns. Path rules see every added, renamed or copied path in each published commit (git rev-list <local> --not --remotes=<remote>), text rules each commit's added lines; waivers only from the base branch allow file; a malformed policy fails closed; visibility caches public 24 h, private 1 h. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
1898142986
commit
67dd3449eb
11 files changed
+653
-3
No files matched your search
@@ -64,6 +64,7 @@ the byte-pinned `/ship` renders in `test/fixtures/golden/`).
|
||||
| `strays.allow` | intentional root files or new top-level directories |
|
||||
| `guards` | `[{ id, when: [globs], command, fix?, timeout_s? }]`: repo commands a lane must pass when a touched file matches `when` (manifest checks, subprocess goldens the import graph cannot see); see [guards](#guards) |
|
||||
| `serial_patterns` | test-file globs the `lanes` check runs one process per file, apart from the unit files (default `**/*.serial.test.*`) |
|
||||
| `sealed` | sealed or eval output that must never reach a public destination; read by the pre-push hook and `gstack-pregate sealed` (see [sealed output](#sealed)) |
|
||||
| `price_file` | repo-relative path of the paid gate's call-plan data file (`GSTACK_EVAL_CALLS v1`); `gstack-eval-plan price-gate` prices from it and never executes anything ([docs/eval-calls.md](eval-calls.md)) |
|
||||
|
||||
Only the `origin/<base>` copy is honoured, so a downgrade is reviewed before it
|
||||
@@ -163,6 +164,52 @@ guard is a *command* with its own fix line. Older gstack refuses unknown keys
|
||||
that reads them ships. The worked gbrain configuration is in
|
||||
[gbrain worked configs](#gbrain-worked-configs).
|
||||
|
||||
<a id="sealed"></a>
|
||||
## Sealed output: the pre-push hook and `gstack-pregate sealed`
|
||||
|
||||
```json
|
||||
{ "sealed": {
|
||||
"paths": ["heldout/**"],
|
||||
"transcripts": ["runs/**/transcript*.jsonl"],
|
||||
"answer_markers": ["SEALED ANSWER:"],
|
||||
"seed_patterns": ["shuffle_seed=\\d+"],
|
||||
"local_paths": true } }
|
||||
```
|
||||
|
||||
A repo with a `sealed` key gets a configured local check against accidental
|
||||
publication whenever the managed pre-push hook (`gstack-redact
|
||||
install-prepush-hook`, no reinstall needed) or the standalone preflight runs:
|
||||
|
||||
```
|
||||
gstack-pregate sealed [--range <a..b>] [--remote origin] [--base <branch>] [--json]
|
||||
```
|
||||
|
||||
- **Boundary.** Every commit the push publishes: `git rev-list <local sha>
|
||||
--not --remotes=<remote>` (and the remote tip when the ref exists); a
|
||||
destination with no refs means everything reachable. `--range` names the
|
||||
commits explicitly.
|
||||
- **Rules.** `sealed.path` and `sealed.transcript` check every path a commit
|
||||
adds, renames or copies, whatever its content (binary, empty, deleted again
|
||||
in a later commit); `sealed.answer`, `sealed.seed` and `sealed.local_path`
|
||||
(`/home/<user>/`, `/Users/<user>/`, `C:\Users\<user>\`) check each commit's added
|
||||
lines. Findings print rule, `file[:line]` and commit, never the text.
|
||||
- **Policy.** The union of the destination base branch's `sealed` and the
|
||||
pushed commit's: a push can tighten it, never relax it. A malformed or
|
||||
unreadable policy refuses. Waivers come only from the base branch's
|
||||
`.gstack/sealed-allow.tsv` (`rule<TAB>path<TAB>sha<TAB>reason`) and are
|
||||
listed on every push.
|
||||
- **Visibility.** `sealed.visibility` from the base branch, else a cache under
|
||||
the state root (`sealed-visibility.json`: a `public` answer for 24 hours, a
|
||||
`private` one for 1 hour before it may turn a refusal into a warning), else
|
||||
`gh repo view --json visibility` (5 s). Unknown, unreadable or newly created
|
||||
counts as public. Public refuses (`SEALED_OUTPUT_REFUSED`, exit 1); private
|
||||
warns.
|
||||
|
||||
Capy's pull-request tool may not run local git hooks, so an agent runs
|
||||
`gstack-pregate sealed` before any push or PR creation in a repo with a
|
||||
`sealed` config (the coordinator contract says so). Hosted CI on the public
|
||||
repository only detects a bypass after the upload.
|
||||
|
||||
<a id="issue-links"></a>
|
||||
## `gstack-issue-links`
|
||||
|
||||
|
||||
@@ -2480,3 +2480,23 @@ downgraded to warn.
|
||||
and do what its `fix` line says, commit, then rerun
|
||||
`gstack-pregate run --allow-repo-commands`. A lane reports done only after this
|
||||
passes and carries the `PREGATE:` line in its handoff.
|
||||
|
||||
<a id="sealed-output-refused"></a>
|
||||
### `SEALED_OUTPUT_REFUSED`
|
||||
|
||||
**Meaning.** The repo declares a `sealed` policy in `.gstack/pregate.json`
|
||||
(base branch ∪ the pushed commit) and a commit this push publishes adds a
|
||||
sealed path or transcript (binary, empty and later-deleted files included), or
|
||||
adds a line with a sealed-answer marker, a seed or a local home path, and the
|
||||
destination is public or its visibility is unknown (a new or unreadable
|
||||
repository counts as public). An unreadable or malformed sealed policy refuses
|
||||
too. The managed pre-push hook and `gstack-pregate sealed` print one line per
|
||||
finding: rule, `file[:line]`, commit. They never print the matched text.
|
||||
|
||||
**Fix.** Remove the output from every published commit before the branch
|
||||
reaches the public repository (a later commit that deletes it still publishes
|
||||
it). A reviewed false positive gets one line in the base branch's
|
||||
`.gstack/sealed-allow.tsv`: `rule<TAB>path<TAB>sha<TAB>reason`. A private
|
||||
destination sets `"visibility": "private"` under `sealed` in the base branch's
|
||||
`.gstack/pregate.json`. Capy's pull-request tool may not run local hooks, so
|
||||
run `gstack-pregate sealed` yourself before any push or PR creation.
|
||||
Reference in new issue
Block a user