Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .agent/skills/09_codex_desktop_governance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Agent Skill 09 - Codex Desktop Governance

This skill documents the repo-local Codex Desktop guardrail layer for this worktree.

## Scope

- Hooks are project-local under `.codex/` and require Codex hook trust before they run.
- The layer is a guardrail, not a complete security boundary.
- GitHub remains read-only unless a human explicitly authorizes otherwise.
- Provider output remains untrusted until human review.

## Allowed Local Commands

Run Rust validation only from `agy7rust/`:

- `cargo fmt --all --check`
- `cargo check`
- `cargo test`
- `cargo clippy -- -D warnings`
- `cargo run --bin agy-ct -- --help`

Normal repo-local reads and searches are allowed. Do not read secrets, token stores, credential files, or `.env` files.

## Blocked Operations

The pre-tool hook blocks:

- `git commit`, `git push`, `git pull`, `git merge`, `git rebase`, `git tag`, and `git fetch`
- GitHub PR, issue, and release write commands
- deploy and release-oriented commands
- environment dumps such as `env`, `printenv`, and `Get-ChildItem Env:`
- `.env`, credential, SSH key, and secret file reads
- `agy-ct run` and `agy-ct benchmark`

## Warnings

The hook layer warns on references to protected documentation, source, and generated artifact paths:

- `README.md`
- `agy7rust/src/`
- `reports/latest.json`
- `reports/performance_baseline.json`
- `artifacts/spark/`
25 changes: 25 additions & 0 deletions .agent/skills/10_generated_artifact_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Agent Skill 10 - Generated Artifact Policy

This skill records how Codex sessions should handle generated CompText artifacts.

## Non-Commit Defaults

Generated runtime files are not automatically commit candidates:

- `reports/latest.json`
- `reports/performance_baseline.json`
- `artifacts/spark/*`
- Rust `target/` outputs

Do not stage or commit generated reports unless the human explicitly approves the exact files.

## Artifact Hygiene

- Prefer validation commands that do not regenerate reports when the task does not require new artifacts.
- Do not run `agy-ct run` or `agy-ct benchmark` during governance-only work.
- Treat generated artifacts as evidence trail material, not source-of-truth implementation.
- Preserve deterministic and replayable outputs; do not fake hashes or rewrite reports to satisfy a claim.

## Claim Hygiene

Generated reports and handoff text may describe local validation results, deterministic packaging behavior, and tamper-sensitive checks when evidenced by commands. They must not claim production readiness, legal proof, forensic certainty, EU AI Act compliance, official SPARK compatibility, or autonomous approval.
2 changes: 2 additions & 0 deletions .codex/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[features]
hooks = true
44 changes: 44 additions & 0 deletions .codex/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|shell_command|functions.shell_command",
"hooks": [
{
"type": "command",
"command": "python .codex/hooks/pre_tool_use_policy.py",
"commandWindows": "py -3 .codex\\hooks\\pre_tool_use_policy.py",
"timeout": 10,
"statusMessage": "Checking repo policy"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash|shell_command|functions.shell_command|apply_patch",
"hooks": [
{
"type": "command",
"command": "python .codex/hooks/post_tool_use_validation.py",
"commandWindows": "py -3 .codex\\hooks\\post_tool_use_validation.py",
"timeout": 10,
"statusMessage": "Checking protected paths"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python .codex/hooks/stop_contract.py",
"commandWindows": "py -3 .codex\\hooks\\stop_contract.py",
"timeout": 10
}
]
}
]
}
}
62 changes: 62 additions & 0 deletions .codex/hooks/post_tool_use_validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""Post-tool warning hook for protected CompText paths."""

from __future__ import annotations

import json
import sys


WATCHED = (
"README.md",
"agy7rust/src/",
"reports/latest.json",
"reports/performance_baseline.json",
"artifacts/spark/",
)


def text_from(value: object) -> str:
if isinstance(value, str):
return value
try:
return json.dumps(value, sort_keys=True)
except TypeError:
return ""


def main() -> None:
try:
event = json.load(sys.stdin)
except json.JSONDecodeError:
return
Comment thread
ProfRandom92 marked this conversation as resolved.
if not isinstance(event, dict):
return

data = " ".join(
[
text_from(event.get("tool_input")),
text_from(event.get("tool_response")),
]
).replace("\\", "/")
hits = [path for path in WATCHED if path in data]
if not hits:
return

print(
json.dumps(
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": (
"CompText artifact hygiene warning: review protected path changes before final handoff: "
+ ", ".join(hits)
),
}
}
)
)


if __name__ == "__main__":
main()
186 changes: 186 additions & 0 deletions .codex/hooks/pre_tool_use_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#!/usr/bin/env python3
"""Repo-local Codex pre-tool policy for comptext-sparkctl."""

from __future__ import annotations

import json
import re
import shlex
import sys
from pathlib import PurePosixPath


BLOCKED_GIT = {
"commit",
"push",
"pull",
"merge",
"rebase",
"tag",
"fetch",
}

BLOCKED_COMMANDS = {
"gh pr",
"gh issue",
"gh release",
"vercel",
"netlify",
"wrangler deploy",
"fly deploy",
"railway up",
"render deploy",
}

SECRET_PATTERNS = (
r"(^|[\s\\/])\.env(\.|$|[\s\\/])",
r"(^|[\s\\/])\.npmrc($|[\s\\/])",
r"(^|[\s\\/])\.pypirc($|[\s\\/])",
r"(^|[\s\\/])\.netrc($|[\s\\/])",
r"(^|[\s\\/])id_rsa($|[\s\\/])",
r"(^|[\s\\/])id_ed25519($|[\s\\/])",
r"(^|[\s\\/])credentials(\.|$|[\s\\/])",
r"(^|[\s\\/])credential-store(\.|$|[\s\\/])",
r"(^|[\s\\/])secrets?(\.|$|[\s\\/])",
)

PROTECTED_WARN_PATHS = (
"README.md",
"reports/latest.json",
"reports/performance_baseline.json",
"artifacts/spark/",
"agy7rust/src/",
)

SAFE_CARGO = (
("cargo", "fmt", "--all", "--check"),
("cargo", "check"),
("cargo", "test"),
("cargo", "clippy"),
("cargo", "run", "--bin", "agy-ct", "--", "--help"),
)


def load_event() -> dict:
try:
event = json.load(sys.stdin)
except json.JSONDecodeError:
return {}
Comment thread
ProfRandom92 marked this conversation as resolved.
if not isinstance(event, dict):
return {}
return event


def normalize_path(value: object) -> str:
if not isinstance(value, str):
return ""
return value.replace("\\", "/").lstrip("./")


def bash_command(event: dict) -> str:
tool_input = event.get("tool_input") or {}
if isinstance(tool_input, dict):
command = tool_input.get("command") or tool_input.get("cmd")
if isinstance(command, str):
return command
return ""


def deny(reason: str) -> None:
print(
json.dumps(
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": reason,
}
}
)
)
raise SystemExit(0)


def warn(message: str) -> None:
print(
json.dumps(
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": message,
}
}
)
)
raise SystemExit(0)


def split_command(command: str) -> list[str]:
try:
return shlex.split(command, posix=False)
except ValueError:
return command.split()


def is_safe_cargo(tokens: list[str], cwd: str) -> bool:
cwd_path = normalize_path(cwd)
in_rust_dir = cwd_path.endswith("/agy7rust") or PurePosixPath(cwd_path).name == "agy7rust"
if not in_rust_dir or not tokens:
return False
lowered = tuple(token.lower() for token in tokens)
return any(lowered[: len(prefix)] == prefix for prefix in SAFE_CARGO)


def command_has_secret_read(command: str) -> bool:
lowered = normalize_path(command).lower()
if re.search(r"\b(printenv|env)\b", lowered) or "get-childitem env:" in lowered:
return True
if re.search(r"\b(get-content|type|cat|more|less|gc|grep|egrep|fgrep|awk|sed|head|tail|jq|yq)\b", lowered):
return any(re.search(pattern, lowered) for pattern in SECRET_PATTERNS)
return False
Comment thread
ProfRandom92 marked this conversation as resolved.


def command_runs_blocked_agy_ct(command: str) -> bool:
lowered = command.lower()
direct = re.search(r"agy-ct(?:\.exe)?(?:\s+--)?\s+(run|benchmark)\b", lowered)
cargo = re.search(r"--bin\s+agy-ct\s+--\s+(run|benchmark)\b", lowered)
return bool(direct or cargo)


def main() -> None:
event = load_event()
command = bash_command(event)
if not command:
return

lowered = command.lower()
Comment thread
ProfRandom92 marked this conversation as resolved.
normalized_lowered = normalize_path(command).lower()
tokens = split_command(command)
token0 = tokens[0].lower() if tokens else ""
token1 = tokens[1].lower() if len(tokens) > 1 else ""

if command_has_secret_read(command):
deny("Blocked by CompText policy: environment, .env, or credential reads are not allowed.")

if token0 == "git" and token1 in BLOCKED_GIT:
deny(f"Blocked by CompText policy: git {token1} is forbidden in this worktree.")

if token0 == "gh" and token1 in {"pr", "issue", "release"}:
deny(f"Blocked by CompText policy: GitHub {token1} writes are forbidden.")

if command_runs_blocked_agy_ct(command):
deny("Blocked by CompText policy: agy-ct run and agy-ct benchmark create generated artifacts.")

if any(blocked in lowered for blocked in BLOCKED_COMMANDS):
deny("Blocked by CompText policy: remote write, release, or deploy command is forbidden.")

if token0 == "cargo" and not is_safe_cargo(tokens, event.get("cwd", "")):
warn("Cargo command is outside the documented validation allowlist; run cargo only inside agy7rust/.")

touched = [path for path in PROTECTED_WARN_PATHS if path.lower() in normalized_lowered]
if touched:
warn("Protected path mentioned; verify human approval and artifact hygiene before editing: " + ", ".join(touched))


if __name__ == "__main__":
main()
Loading
Loading