feat: moat partner hardening — granted-repo scanning, secrets zero-policy, evict-then-guard tasks - #1425
Conversation
…licy, evict-then-guard tasks moat-audit.py now reads the ACCESS registry (one knob: LIMEN_GITVS_ACCESS): partner-granted repos are audited regardless of visibility (a partner's eyes make the tree exposed), carry a names-only Actions-secrets zero- policy (RED on any repo secret — a push collaborator can exfiltrate via a workflow edit; re-home is L-PARTNER-GRANTS work), and cite guard-owed when granted without a moat-guard entry. --require-guard makes the evict-then-guard end-state an executable predicate for the two seeded CONST-*-MOAT board tasks. estate.yaml classes both shared private repos operation_private so protection posture applies (was protection-exempt private_unreviewed). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Multi-agent review roll call (CodeRabbit and Claude review automatically. Reviewers: post substantive findings only. Authors/agents: address every thread, push fixes to this branch, reply and resolve, then re-request review.) |
|
To use Codex here, create a Codex account and connect to github. |
CodeQL taints anything returned by the /actions/secrets endpoint, so
even printing the count flags py/clear-text-logging-sensitive-data.
Posture is selected by branching ('clean'/'exposed'), which is also
the tighter output discipline: nothing derived from the endpoint ever
reaches a log line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d1218b57c9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| res = subprocess.run( | ||
| ["gh", "api", f"repos/{repo}/actions/secrets", "--jq", ".total_count"], | ||
| capture_output=True, text=True, | ||
| ) |
There was a problem hiding this comment.
Handle missing gh in the secrets probe
When PyYAML successfully marks a repo as granted but the runner does not have gh on PATH, this new subprocess.run([...]) raises FileNotFoundError instead of behaving like repo_visibility, which treats missing GitHub CLI access as unknown. That makes scripts/moat-audit.py --repo <granted> --require-guard crash before it can report guard/leak status, so local or minimal runners without the GitHub CLI cannot execute the new moat predicates unless they remember --no-visibility; catch missing CLI/timeouts and return a skipped/unknown count instead.
Useful? React with 👍 / 👎.
| receipt="git:organvm/limen:moat-guard.json", | ||
| ), | ||
| dict( | ||
| id="CONST-CANNIBAL-MOAT", |
There was a problem hiding this comment.
Seed moat work for every granted repo
This added block creates --require-guard tasks for only the Jessica and Scott grants, but institutio/github/access.yaml also grants organvm/sovereign-systems--elevate-align, and moat-guard.json has no entry for it. The default audit merely reports that repo in guard_owed and still exits 0 unless --require-guard is run for that specific repo, so the Maddie partner-visible repo never gets a blocking eviction/guard task from this seeder; add the third row or derive these rows from ACCESS.
Useful? React with 👍 / 👎.
| try: | ||
| import yaml | ||
| grants = (yaml.safe_load(ACCESS.read_text(encoding="utf-8")) or {}).get("grants") or {} | ||
| return {str(r) for r in grants} | ||
| except Exception: | ||
| return set() |
There was a problem hiding this comment.
Do not silently drop granted repos without PyYAML
If PyYAML is unavailable or the import fails, this broad except returns an empty grant set, so every new partner-specific guard in this change is bypassed: granted private repos are not scanned, guard_owed stays empty, and the secrets zero-policy is never checked. moat-audit.py previously ran with only stdlib dependencies, so minimal/local predicate runners can now report green while ignoring ACCESS entirely; fail loudly when ACCESS exists but cannot be parsed, or add a stdlib fallback for this simple grants mapping.
Useful? React with 👍 / 👎.
| if res.returncode != 0: | ||
| return None |
There was a problem hiding this comment.
Fail closed when secret counts are unreadable
For a partner-granted repo, a nonzero exit from gh api repos/<repo>/actions/secrets can mean the token lacks permission to list secrets, but this path returns None and the caller treats that the same as zero secrets. In that scenario the new zero-policy check passes even though it never proved the repo has no Actions secrets; unless --no-visibility was explicitly requested, propagate an unreadable/unknown secret count as a failing result instead of excluding it from secrets_exposed.
Useful? React with 👍 / 👎.
| lure_gaps = [r for r in results if r["lure"] in ("gap", "dark")] | ||
| guard_owed = [r for r in results if r["guard_owed"]] | ||
| secrets_exposed = [r for r in results if r["repo_secrets"]] | ||
| guard_missing = [r for r in results if args.require_guard and not guard_repos.get(r["repo"])] |
There was a problem hiding this comment.
Require real patterns for guard completion
With --require-guard, this only checks that the moat-guard row is truthy, so a repo can satisfy the new CONST-*-MOAT done predicate by adding a row that contains just note or scan_paths and no leak_patterns; scan_leaks() then returns no_patterns with no hits, and the audit passes without asserting any tuned value is absent. For the evict-then-guard tasks, require at least one declared leak pattern before considering the guard present.
Useful? React with 👍 / 👎.
PR 3 of the partner-partition plan (reads #1407's ACCESS registry; independent of #1423).
guard_owedcite when a granted repo has no moat-guard entry;--require-guardflag = the executable done-predicate for evict-then-guard work.repo_overridesclasscontent-engine--asset-amplifier+sovereign-systems--elevate-alignasoperation_private(they fell to protection-exemptprivate_unreviewed).CONST-STYX-MOAT+CONST-CANNIBAL-MOATrows — evict the tuned values FIRST, then guard (a guard entry for an in-tree value reddens instantly, which is why no guard entries land in this PR).public-record-data-scrapperleaks 4 declared values (red on main before this diff) — homed as board taskHEAL-SCRAPPER-MOAT-EVICT(system_debt, broker-acknowledged).Verification: py_compile green; seeder dry-run validates both MOAT rows through the intake contract;
gitvs doctor --parity-onlydrift == ∅; live audit exercises every new path (granted=partner marks, guard-owed cites, secrets 0);verify-scoped.sh→ Scoped verification passed.🤖 Generated with Claude Code