comgu

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

ConstraintWhy
Path and extension allowlistsOnly the five commerce configs are writable
No traversal, no absolute paths../ and /etc/… are refused before any write
No symlink escapeIncluding a symlinked directory along the path
The authoritative catalog is unpatchableThe source of truth is never a remediation target
Isolated workspaceThe real checkout is never edited in place
Clean environment, timeoutValidation inherits no credentials
Redacted outputAnything 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.