Mint instructions — R2 portfolio-image-promotion

Why: decoupled, guard-railed credential for Claude Code to do ongoing portfolio image-promotion work (dare → dogwood → audrey) without reaching into the Private vault. Follows the layered guard-rail stack — see feedback_layered_guardrail_stack.md.

One-time setup. Estimated time: ~3 minutes at CDN, security layer, and DNS provider sitting in front of dare.co.uk.">CF dashboard + ~1 minute in 1Password desktop.

Layered scope summary

Layer What it allows What it blocks
Secret-store Code Shared vault (Claude SA can read) Private vault stays untouched
Resource Buckets dare-images, dogwood-photos only All other buckets (edge, xlabs, future client buckets)
Operation Object Read & Write Bucket create/destroy, account admin
Wrapper ~/bin/r2-portfolio-promote (to build, post-mint) Free-form aws s3 shell calls

Step 1 — Mint at Cloudflare (R2-native token UI, not Custom Token)

URL: https://dash.cloudflare.com/2366f43fb08cc98065551599ad8e6e63/r2/api-tokens

Click: Create API token

Settings: - Token name: portfolio-image-promotion - Permissions: Object Read & Write (do NOT pick Admin) - Specify bucket: Apply to specific buckets only → tick: - ✅ dare-images - ✅ dogwood-photos - ❌ leave edge and xlabs unticked - TTL: blank (no expiry — revisit at the 8th-of-month safety review) - Client IP filter: blank

Capture all four values before closing the modal — Cloudflare shows the secret exactly once: 1. Access Key ID 2. Secret Access Key 3. Token value (R2-native; usually unused if using aws s3 style access, capture anyway) 4. S3-compatible endpoint URL (https://2366f43fb08cc98065551599ad8e6e63.r2.cloudflarestorage.com)

Step 2 — Store in 1Password desktop app

op CLI can’t create items in service-token mode — has to be the desktop UI (per feedback_1password_desktop_for_new_tokens).

Label Type Value
access_key_id text from step 1
secret_access_key CONCEALED from step 1
token CONCEALED from step 1
endpoint text https://2366f43fb08cc98065551599ad8e6e63.r2.cloudflarestorage.com
buckets text dare-images, dogwood-photos
valid from date today (2026-05-14)
notes text “Portfolio image promotion — Object R/W on dare-images + dogwood-photos. Re-mint when audrey-images comes online. Spec: ~/Downloads/mint_r2_portfolio_token_2026-05-14.md”

Step 3 — Verify (you do this; ping me when done)

After the 1Password item is saved, run this — it round-trips the credential and tries a no-op list:

AWS_ACCESS_KEY_ID=$(op read "op://Code Shared/R2 portfolio-image-promotion/access_key_id") \
AWS_SECRET_ACCESS_KEY=$(op read "op://Code Shared/R2 portfolio-image-promotion/secret_access_key") \
aws s3 ls s3://dare-images/ \
  --endpoint-url "https://2366f43fb08cc98065551599ad8e6e63.r2.cloudflarestorage.com" \
  --region auto \
  | head -5

Expected: a list of objects (or empty if bucket is empty). 403 means token scope is wrong. 404 means bucket name typo.

Step 4 — What Claude does next (after you confirm verified)

  1. Use the token to list contents of the edge bucket — wait, this token doesn’t include edge. Decision needed: either add edge to the include list at mint time (if the Tier 1 image lift will go there), OR migrate the 3 edge/* images into dare-images under a clean edge/ prefix and retire the edge bucket entirely. Recommend the latter — fewer surfaces to guard, fewer hostnames to wire.
  2. Verify whether the 3 Tier 1 images already exist in dare-images or edge bucket (cheap probe before any upload).
  3. Apply SEO-naming convention (debating-glass-room-thumb.jpg, henri-cartier-bresson.jpg, steven-soderbergh.jpg).
  4. Upload via aws s3 cp ... s3://dare-images/edge/... to dare-images bucket.
  5. Rewrite the 3 HTML refs from wp-content/uploads/edge/*images.dare.co.uk/edge/* (or whatever the production CDN hostname is).
  6. Move on to Tier 2 (17 sitemap-referenced uploads).

Rollback / revocation

Single click at the same R2 tokens page → Revoke. The op://Code Shared/R2 portfolio-image-promotion/* references will start returning auth errors immediately; no caching to worry about. Update or delete the 1Password item if revoked.


Mint-once, scope-narrow, verify-then-trust. The credential never leaves your screen and the desktop app; the secret-store layer keeps it from anywhere Claude shouldn’t reach.

Source: mint_r2_portfolio_token_2026-05-14.md · Rendered 2026-05-14 08:22