Skip to content

Rebrand AOS to ACS across all documentation and files#1

Merged
rocklambros merged 8 commits into
mainfrom
dev
Apr 10, 2026
Merged

Rebrand AOS to ACS across all documentation and files#1
rocklambros merged 8 commits into
mainfrom
dev

Conversation

@rocklambros

Copy link
Copy Markdown

Summary

  • Renamed Agent Observability Standard → Agent Control Standard in all content
  • Replaced AOS → ACS in filenames, directories, code examples, and references
  • Updated URLs: aos.owasp.org → agentcontrolstandard.org
  • Updated repo references to Agent-Control-Standard/ACS
  • Renamed files: docs/aos.mdacs.md, specification/AOS/ACS/, AOS_in_action_example.mdACS_in_action_example.md

Test plan

  • Verify all documentation renders correctly on agentcontrolstandard.org
  • Confirm no remaining AOS references via search
  • Validate mkdocs.yml navigation paths resolve

lanasalameh1 and others added 8 commits September 28, 2025 18:16
Update aos_schema.json, add url to MCPServer object
- Rename Agent Observability Standard → Agent Control Standard
- Replace AOS → ACS in all content, filenames, and directories
- Update URLs: aos.owasp.org → agentcontrolstandard.org
- Update repo references to Agent-Control-Standard/ACS
@rocklambros rocklambros merged commit 87aeccf into main Apr 10, 2026
bar-capsule added a commit to bar-capsule/ACS that referenced this pull request Jun 17, 2026
Two passes folded into one commit because they share helper code.

## Pass A — Security review (SECURITY.md threat model + tests + fixes)

12-threat model documented in adapters/SECURITY.md. 5 code fixes for
high-priority threats; 7 out-of-scope items documented honestly.

- T5 SSRF via ACS_GUARDIAN_URL: validate_guardian_url() allowlist
  (http/https only); called from every adapter's call_guardian and
  from do_handshake / ping in _common.
- T6 Guardian DoS via oversized request body: MAX_REQUEST_BODY_BYTES
  (1 MiB) cap, matching the handshake's max_payload_size_bytes
  advertisement. Refuses Content-Length > cap with HTTP 413.
- T7 leaky HMAC secret file: _check_secret_file_perms() refuses
  mode & 0o077 != 0, wrong owner, or symlink. Raises
  SecretFilePermissionsError instead of silently using a leaked key.
- T8 cache poisoning: save_session_state and do_handshake create
  cache dirs mode 0700 and files mode 0600 via os.open(O_CREAT, 0o600)
  so other local users can't read or poison adapter state.
- T9 regex DoS via huge command: scan_destructive_bash_safely()
  refuses inputs > 8 KiB, emits audit event, returns
  "input_too_large" sentinel — caller MUST treat as suspicious.

16 new tests in _common/tests/test_security.py, each named for the
specific attack it falsifies.

## Pass B — Harsh-reviewer audit + 3 production failure modes + fixes

Stepped back from the work, audited as a hostile reviewer. Identified
the 3 most-likely production failure modes; wrote tests that fail on
the current code; fixed the bugs.

- BUG Agent-Control-Standard#1 NAT _correlation_request_id collision: the old uuid5-from-
  (session, function, kwargs-hash) was deterministic. Two calls to
  the same tool with the same args (list_files(), get_status(), any
  idempotent tool — very common) produced identical request_ids and
  the Guardian's replay protection rejected the second with
  REPLAY_DETECTED. Fix: stash a fresh uuid4 on the context in
  pre_invoke; post_invoke reads it back. Per-call uniqueness + pre/
  post correlation both preserved.
- BUG Agent-Control-Standard#2 Guardian state lost on restart: GuardianState was RAM-only.
  A Guardian restart (deploy / OOM / autoscaling roll) wiped
  seen_request_ids, opening a replay window for every previously-sent
  envelope. §10.3 doesn't pause for the duration of a deploy. Fix:
  per-session state persisted to a JSON file under
  ACS_GUARDIAN_STATE_DIR (default ~/.cache/acs-guardian-state/),
  mode 0700/0600. State loads on first session-touch, persists on
  every mutation in check_replay and append_to_chain.
- BUG Agent-Control-Standard#3 lifecycle subscription race: _ensure_lifecycle_subscribed
  was a check-then-set with no lock. Two parallel pre_invoke calls
  (normal in NAT) both saw _lifecycle_subscribed=False and both
  subscribed; every WORKFLOW event then fired its ACS lifecycle hook
  twice. Fix: threading.Lock around the check-then-set, with re-check
  inside the lock.

4 new tests in nat/tests/test_failure_modes.py: 3 for the failure
modes above, 1 regression guard ensuring the BUG Agent-Control-Standard#1 fix preserves
pre/post correlation (post_invoke's request_id_ref must equal
pre_invoke's request_id, per tool-call-result.json:19-23).

## Test-strengthening: catching 2 mutations that previously slipped

Two mutation tests passed previously because of weaknesses in the
tests themselves:

- RollingChain::test_chain_hash_links_consecutive_requests only
  asserted hashes differed. Dropping previous_hash from the chain
  still produced different per-request hashes, so the mutation slipped.
  Strengthened test_chain_is_recomputable now EXTERNALLY recomputes
  the expected chain hash across 3 entries (now possible because the
  Guardian uses the client's timestamp) and asserts byte-equality.
  Also asserts the published hash does NOT match the "no
  previous_hash" computation.
- Cursor envelope-schema fixtures all used SESSION_UUID, so a
  skip-coercion mutation slipped. Added
  UuidCoercionForNonUuidCursorIds (2 tests) with conv-abc123 /
  chat_xyz / test-cc-session inputs, asserting the adapter coerces
  them to valid UUIDs and that the coercion is deterministic.

## Test counts after this commit (all green, zero hidden skips)

  _common:            16 security
  claude-code:        32 round-trip + envelope-schema
  cursor:             50 round-trip + envelope-schema + uuid-coercion
                      (1 intentional manual-Cursor skip)
  example-guardian:   20 spec-compliance
  nat:                24 (test_adapter 7 + test_live 5 +
                          test_envelope_schema 6 + test_lifecycle 2 +
                          test_failure_modes 4)

  Total: 142 tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bar-capsule added a commit to bar-capsule/ACS that referenced this pull request Jun 17, 2026
Each item has a falsifying test in adapters/_common/tests/test_edge_cases.py
(17 tests total). Items not requiring code changes still have tests that
codify the safe behavior so a future regression would be caught.

## Items 1-12

Agent-Control-Standard#1  rfc8785 JCS consistency — test confirms fallback matches the
    rfc8785 package byte-for-byte on every ACS envelope shape we ship.
    No code change needed; a mixed-install signature mismatch would
    surface as test failure.

Agent-Control-Standard#2  Guardian regex DoS, server-side: _matches_destructive_bash now
    returns "too_large" for inputs > DESTRUCTIVE_SCAN_MAX_LEN (8 KiB).
    The Guardian denies with reason_codes=["input_too_large"] —
    fail-safe direction. Previously, _common had the cap but the
    Guardian iterated patterns directly, leaving the server unprotected.

Agent-Control-Standard#3  HA Guardian replay window: persist() now takes an exclusive flock
    on a .lock sidecar, re-reads on-disk state, merges (union of
    seen_request_ids / seen_nonces with earliest-timestamp wins), and
    atomically writes. check_replay re-reads the state on every call
    so Guardian A's writes are visible to Guardian B within one
    request. Cross-instance replay window closed under shared
    ACS_GUARDIAN_STATE_DIR.

Agent-Control-Standard#4  Unbounded seen_request_ids: switched to dict {rid: timestamp}.
    New evict_old_request_ids() drops entries older than 2 × skew
    window (replay impossible past skew anyway). check_replay calls
    eviction opportunistically every 100 inserts. Memory bound is now
    O(skew_window / inter-request-time), not unbounded. Backwards-
    compat for list-format state files preserved.

Agent-Control-Standard#5  Handshake cache TTL: do_handshake skips cache files older than
    ACS_HANDSHAKE_CACHE_TTL_SECONDS (default 3600s). Operator config
    changes propagate within the TTL.

Agent-Control-Standard#6  NAT id(context) collision: WeakKeyDictionary fallback for
    contexts that reject attribute assignment. Last-resort path
    (object isn't weak-referenceable either) returns a fresh uuid4
    per call and emits an audit event — pre→post correlation is
    lost in that path, but no silent collision.

Agent-Control-Standard#7  Unicode / NULL / surrogate round-trip: emoji, NULL bytes, multi-
    plane unicode all sign+verify cleanly. JCS handles them via
    UTF-8 encoding; no code change needed.

Agent-Control-Standard#8  ISO 8601 parse resilience: parse_iso8601 already accepts Z suffix,
    timezone offsets, millisecond + microsecond precision. Test
    codifies the accepted shapes + asserts garbage is rejected.

Agent-Control-Standard#9  ACS_GUARDIAN_HOST_ALLOWLIST: optional env-var allowlist that
    restricts validate_guardian_url to specific hostnames in addition
    to the http/https scheme check. Defense in depth against env-var
    attacks that smuggle a valid http:// URL to internal services.

Agent-Control-Standard#10 Cursor session-state file collision: _session_state_path now
    accepts an optional workspace parameter folded into the hash key.
    Cursor adapter passes the workspace_path / cwd so two Cursor
    windows with the same non-UUID conversation_id can't share state.

Agent-Control-Standard#11 Guardian envelope schema validation: if jsonschema + ACS_SPEC_DIR
    are available, every incoming envelope is validated against
    request-envelope.json before policy evaluation. Malformed envelopes
    rejected with -32600 Invalid Request. system/ping and
    handshake/hello exempt because their payload shapes differ.

Agent-Control-Standard#12 State-file hash length: bumped _session_state_path and
    _handshake_cache_path hashes from sha256[:16] (64-bit) to full
    sha256 (256-bit). Eliminates birthday collisions over deployment
    lifetime.

## Test counts after this commit (all green, 1 intentional manual skip)

  _common:            33 (16 security + 17 edge-cases)
  claude-code:        32
  cursor:             50
  example-guardian:   20
  nat:                24

  Total: 159 tests.

## Side-effects of the fixes

- Round-trip test fixtures updated to use real UUID session_ids
  (claude-code/test_adapter.py). Old "test-cc-session" fails the new
  Guardian-side envelope-schema check, which is correct — non-UUID
  session_ids never reached the Guardian from real Claude Code.
- Cursor adapter wires workspace through to load/save/record session
  state for Agent-Control-Standard#10 (new _workspace helper).
- example_guardian.py imports DESTRUCTIVE_SCAN_MAX_LEN from acs_common
  to keep the cap in one place.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants