Security
An agent that writes code, kept on a short leash
Comgu generates patches and opens pull requests. Everything below exists because that is only safe if the agent's authority is narrow and enforced by the system rather than by the prompt.
The model cannot widen its own authority
Registered templates only
The model selects from templates the patcher implements. An unregistered name is rejected by schema validation and the deterministic plan is used instead.
Registered commands only
Validation runs command ids from a fixed registry. There is no path from a model, a finding, or a DataHub description to a shell string.
Grounded in real findings
Every proposed action must cite a finding Comgu produced deterministically. A plan referencing an invented finding is discarded.
Catalog text is untrusted input
Descriptions and documentation are data, not instructions. A test asserts that a model obeying injected instructions still cannot get an unregistered template executed.
The patch sandbox
| Constraint | Why |
|---|---|
| Path and extension allowlists | Only the five commerce configs are writable |
| No traversal, no absolute paths | ../ and /etc/… are refused before any write |
| No symlink escape | Including a symlinked directory along the path |
| The authoritative catalog is unpatchable | The source of truth is never a remediation target |
| Isolated workspace | The real checkout is never edited in place |
| Clean environment, timeout | Validation inherits no credentials |
| Redacted output | Anything resembling a token is masked before storage |
The human gate is structural
Not a convention, and not a hidden button — a property of the state machine.
AWAITING_APPROVAL → { APPROVED, REJECTED, CANCELLED } # no PATCH_GENERATING
VALIDATION_FAILED → { AWAITING_APPROVAL, FAILED, CANCELLED } # no PULL_REQUEST_*
live:mutate is a capability the judge role does not hold.
Whether an approval may open a real pull request is decided from the caller's
capabilities, then passed into the runner. A judge approving on an instance
configured for live pull requests still gets a dry run — and a worker resuming
a run has no approving principal, so it stays dry too.
Webhooks and secrets
Signature verification
HMAC-SHA256 over the raw body with a timing-safe compare. A re-serialised payload fails, as it should. Rejected deliveries are recorded and never processed.
Idempotency
Duplicate deliveries collapse onto the existing event rather than starting a second workflow.
Read-only Shopify scopes
Comgu proposes pull requests; it never writes to a store. No write scope is requested.
Secrets are referenced, not stored
The database holds env:GITHUB_TOKEN, never the value. A test
asserts no secret reaches persistence.
The security suite is a single file you can read in one sitting: tests/security.