aws-samples / aws-samples/sample-autonomous-cloud-coding-agents
feat(observability): CI guard to enforce attributed SDK client construction (#319 follow-up)
- Dominant language
- TypeScript
- Stars
- 143
- Forks
- 46
- Avg merge
- 3d 9h
- Merged PRs (30d)
- 20
Description
## Problem
#319 (PR #345) routes every AWS SDK client through an attributed factory (`makeClient`/`makeDocClient` in TS; `tenant_client`/`platform_client` in Python) so no outbound AWS call loses solution attribution. But that invariant is currently **convention-only** — a contributor can still write a naked `new S3Client({})` / `boto3.client(...)` and it compiles, passes tests, and works, silently losing attribution. This is exactly how the pattern decayed before: 5 naked SDK sites appeared on `main` *while #345 was in review*.
The factory is the easy path; this issue adds the **hard gate** that makes a naked client fail the build.
## Proposed enforcement (mirrors the repo's existing invariant-regression pattern)
- `scripts/check-ua-coverage.mjs` modeled on `scripts/check-types-sync.ts` — scans `cdk/src` + `cli/src` (TS) and `agent/src` (Python) for client construction outside the helper modules; exits non-zero on any naked site. Wire into `mise.toml` `drift-prevention` (a `build` dependency) + a `repo:local` prek hook.
- **Note:** use git-pathspec `'cdk/src/' 'cli/src/'` (directory prefix), **not** `'cdk/src/**/*.ts'` — the `**/*.ts` glob does not match files directly under `src/` and hid a bypass during #345 review (`cli/src/webhook-test.ts`).
- ESLint `no-restricted-syntax` `NewExpression[callee.name=/Client$/]` in `cdk/eslint.config.mjs` + `cli/eslint.config.mjs`, with an override disabling it in the `ua.ts` helper files (sharper than the script for the TS side).
- Python side via ruff `flake8-tidy-imports` banned-api or a `.semgrep/` rule (the latter gives the `# nosemgrep: -- ` allowlist the repo already documents).
- Optionally a ratchet-baseline variant (like `scripts/check-deadcode-ratchet.mjs`) only if debt must remain temporarily; #345 leaves the census at zero, so a hard gate should be feasible immediately.
## Acceptance
- A PR that adds a naked `new XxxClient({})` (cdk/cli) or `boto3.client(...)` (agent, outside `aws_session.py`) fails `mise run build` and the prek hook.
- The three `md/` sanitizers stay locked identical via a shared cross-language fixture.
## Context
- Builds on #319 / PR #345 (the factory).
- Depends on nothing; #345 should merge first so the census is already zero.
Contributor guide
Research direction
Start by reading scripts/check-types-sync.ts and scripts/check-deadcode-ratchet.mjs, then inspect mise.toml, cdk/eslint.config.mjs, and cli/eslint.config.mjs. Check the existing client helpers and the three md/ sanitizers before running mise run build and the repo:local hook. Done means naked TypeScript or Python SDK construction fails both checks and the sanitizer fixtures remain identical.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, eslint, python, typescript
- Domain
- build-system, ci-cd, observability, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100