feat(settings): per-repo override of the global agent-freeze kill-switch - #4375
Merged
Conversation
global_agent_controls.frozen has no per-repo scoping today -- flipping it affects every repo at once, which caused a real multi-repo incident where live merge/close actions fired for repos meant to stay paused. Adds agentGlobalFreezeOverride (RepositorySettings + .gittensory.yml settings: block, global-default + per-repo-override like every other gate setting): when a repo opts in, it bypasses the DB-backed freeze while every other repo stays frozen. The AGENT_ACTIONS_PAUSED env var and a repo's own agentPaused still always win over the override. Threaded through every real enforcement path: the executor's AgentActionExecutionContext/IssueActionExecutionContext, the shared resolveRepoActionMode helper, and all direct resolveAgentActionMode call sites in processors.ts, agent-approval-queue.ts, contributor-issue-draft.ts, and the MCP automation-state tool.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | f49ea74 | Commit Preview URL Branch Preview URL |
Jul 09 2026, 05:36 AM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4375 +/- ##
=======================================
Coverage 93.95% 93.95%
=======================================
Files 400 400
Lines 36820 36823 +3
Branches 13452 13454 +2
=======================================
+ Hits 34595 34598 +3
Misses 1569 1569
Partials 656 656
🚀 New features to boost your workflow:
|
…gs API agentGlobalFreezeOverride is an operator-only emergency lever (set via the private .gittensory.yml, never a repo maintainer) but had landed in maintainerSettingsSchema, whose PUT /v1/repos/:owner/:repo/settings endpoint only requires repo write access -- any maintainer could set it directly, bypassing the operator-only restriction the field exists for. Drop it from that schema; the yml-only config-as-code path is the sole intended write mechanism.
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Merged
16 tasks
This was referenced Jul 9, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
global_agent_controls.frozen(the DB-backed operator kill-switch) has no per-repo scoping today — flipping it affects every repo at once. That caused a real multi-repo incident tonight: a global unfreeze meant for one repo let live merge/close actions fire against repos meant to stay paused.agentGlobalFreezeOverride(newRepositorySettingsfield +.gittensory.ymlsettings:block entry): a repo can opt in to bypass the DB-backed freeze while every other repo stays frozen — the same global-default + per-repo-override shape every other gate/settings field already uses.AGENT_ACTIONS_PAUSED(the env-var hard stop) is never overridable by any per-repo setting. A repo's ownagentPaused: truestill always wins over its own override.AgentActionExecutionContext/IssueActionExecutionContext(the executor), the sharedresolveRepoActionModehelper, and all directresolveAgentActionModecall sites acrossprocessors.ts,agent-approval-queue.ts,contributor-issue-draft.ts, and the MCP automation-state tool.isDbFrozenForRepo(env, override)helper indb/repositories.tscentralizes the bypass logic.Scope
0127_agent_global_freeze_override.sqlRepositorySettingstype, OpenAPI schemas + routespackages/gittensory-engine) yml resolver + type mirror.gittensory.yml.example+config/examples/gittensory.full.ymldocumentation (kept byte-synced)maintainer-settings.tsx) — this is an emergency operator-only lever set via the private per-repo.gittensory.yml, not something a repo maintainer should self-serve during an active incident freeze.Validation
npx tsc --noEmit -p .— cleannpm run db:migrations:check/npm run db:schema-drift:check/npm run manifest:drift-check— cleannpm run ui:openapi(regenerated) /npm run ui:openapi:settings-parity— cleannpm run test:engine-parity/npm run test --workspace @jsonbored/gittensory-engine— all passnpm run test:coverage(full unsharded) — 625 files / 12377 tests pass, 0 failed, exit 0, all thresholds (90% floor) exceededisDbFrozenForRepoboth branches, the executor bypasses-freeze-but-not-env-var-or-own-pause matrix (4 new tests inagent-action-executor.test.ts),resolveRepoActionModeoverride matrix, DB round-trip (insert/update/default) indata-spine.test.ts, and the ymlsettings:parse +resolveEffectiveSettingsoverride infocus-manifest.test.tsSafety
AGENT_ACTIONS_PAUSED) verified non-overridable by a dedicated regression testagentPausedverified to still win over its own override (dedicated regression test)