test(smoke): verify bytes-after-delete and bytes-after-expiry#8
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
WalkthroughThis PR implements artifact expiration and R2 object cleanup across the system. It adds a Sequence Diagram: Artifact Deletion with R2 PurgesequenceDiagram
participant Client
participant ApiHandler as API Handler (deleteArtifact)
participant Database as Database
participant R2 as R2 Bucket
Client->>ApiHandler: DELETE /artifacts/{id}
ApiHandler->>Database: deleteArtifact(id)
Database-->>ApiHandler: {artifact_id, deleted_at}
ApiHandler->>R2: list(prefix: artifacts/{id}/...)
R2-->>ApiHandler: [keys...], cursor
ApiHandler->>R2: delete([keys...])
R2-->>ApiHandler: deleted count
ApiHandler-->>Client: {artifact_id, deleted_at, deleted_r2_objects}
Sequence Diagram: Artifact TTL Cleanup with R2 PurgesequenceDiagram
participant Admin
participant ApiHandler as API Handler (cleanup)
participant Database as Database
participant R2 as R2 Bucket
participant KV as Denylist KV
Admin->>ApiHandler: POST /admin/cleanup
ApiHandler->>Database: getExpiredArtifacts()
Database-->>ApiHandler: [artifact_ids...]
loop per artifact_id (string)
ApiHandler->>ApiHandler: deny(artifact_id)
ApiHandler->>KV: put(denykey)
ApiHandler->>R2: purgeArtifactBytes(prefix: artifacts/{id}/...)
R2-->>ApiHandler: deleted count
end
ApiHandler-->>Admin: {deleted_r2_objects: total_count}
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
The PR-preview deploy uses ad-hoc per-PR worker names (agent-paste-api-pr-N), so the env-scoped vars in apps/api/wrangler.jsonc don't apply. Without AGENT_PASTE_ENV the new isNonProductionEnv check defaults to fail-closed and returns 404 on /__test__/* routes, breaking the bytes-after-delete smoke. Inject the var here so PR previews behave like the preview environment. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
agent-paste PR preview is ready. API: https://agent-paste-api-pr-8.isaac-a46.workers.dev |
The new assertActorRateLimitFires helper exhausts the actor's 60/min budget by hammering an upload mutation. The next assertion, assertBytesPurgedAfterExpiry, republishes through the same user API key and was hitting rate_limited_actor at the publish step. Reorder so the rate-limit probe runs last; bytes-after-delete and -after-expiry now run on a fresh budget. Also reconcile docs/ops/project-status.md: PR #6 (CSP) and PR #8 (bytes-after-delete/expiry) closed two backlog items without updating this doc. Moved both into Recently Completed and renumbered. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ting (#9) * fix(api,upload): replay idempotent mutations before rate-limit accounting Adds a SELECT-only peekIdempotentReplay helper to @agent-paste/commands and uses it in both upload mutation routes to short-circuit known-good retries before either rate-limit binding is touched. Hosted smoke now hammers POST /v1/upload-sessions with unique idempotency keys to confirm 429 with the rate_limited_actor envelope on preview targets. * docs(status): close out item #1 and renumber backlog PR #9 finished the rate-limit work, so mark ADR 0039/0064 done, drop the backlog entry, and shift items #2-#11 down one slot. Updates the phase partition note to match the new numbering. * debug: dump content fetch context on failure Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: drop temporary debug print from smoke-hosted Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(smoke): run rate-limit probe after purge tests; reconcile backlog The new assertActorRateLimitFires helper exhausts the actor's 60/min budget by hammering an upload mutation. The next assertion, assertBytesPurgedAfterExpiry, republishes through the same user API key and was hitting rate_limited_actor at the publish step. Reorder so the rate-limit probe runs last; bytes-after-delete and -after-expiry now run on a fresh budget. Also reconcile docs/ops/project-status.md: PR #6 (CSP) and PR #8 (bytes-after-delete/expiry) closed two backlog items without updating this doc. Moved both into Recently Completed and renumbered. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(smoke): fire rate-limit probe in parallel waves Sequential 120 attempts at ~2/sec spread across multiple Cloudflare worker isolates means no single isolate ever sees the 60-in-60s threshold. Replace the serial loop with four parallel waves of 80 requests each. The burst forces a single isolate's counter past the limit before the trailing window slides. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
biome lint rule noUnusedFunctionParameters surfaces on cache miss. PR #8 landed via cache hit; downstream PRs with cache misses fail Validate.
* docs(ops): bootstrap hosting checklist for click-ops hand-off Enumerates DNS verification, Bitwarden vault entries, GitHub Production environment approval policy, and end-to-end verification for backlog item #8 so the human click-ops takes minutes instead of hours. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(ops): correct non-sensitive identifier guidance for GH org inheritance --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Backlog item #7: smoke tests now assert R2 bytes are actually purged after artifact delete and after expiry-driven cleanup, closing the ADR 0048 partial state.
Done
pnpm smoke:localandpnpm smoke:hosted(preview target) cover the full purge path: artifact has R2 objects → admin delete (or force-expire + scheduled cleanup) → R2 prefix empty → signed URL 404 → denylist KV entry present.apps/api/src/index.tscleanup handler +deleteArtifactroute now callpurgeArtifactBytes(env, artifactId); previously cleanup wrote denylist entries but left bytes.packages/db/src/index.tsgainsforceExpireArtifacton both Local and Postgres repositories.pnpm verifygreen (49/49).Test-only routes
POST /__test__/force-expire,GET /__test__/r2-list,GET /__test__/denylist. Double-gated:isNonProductionEnv(env)returnsfalseforAGENT_PASTE_ENV === "production" | "live"and when the var is unset (fail-closed).apps/api/wrangler.jsoncsets"production"on the production env and"preview"on preview.authenticateAdminbearer-token check.Files
apps/api/src/index.tsapps/api/wrangler.jsoncpackages/db/src/index.tsscripts/local-mvp-server.mjsscripts/smoke-local-mvp.mjsscripts/smoke-hosted.mjsSummary by CodeRabbit