TODO¶
The accepted-risk record for the HybridCloudWorks website, and the index to where the open work lives. Engineering work, owner decisions, production approvals, credentials, external access and live-environment operations are GitHub issues; verified completion belongs in CHANGELOG.md, and the required-inputs inventory is Required-Inputs on the docs site.
Open work is tracked in GitHub issues as of 2026-09-05. Owner decision:
the remaining items were moved to the issues list so they can be worked from
there, and this file now holds only what is not work — the accepted risks
below, which are decisions to live with something and must stay written down —
plus the pointers that follow. The tracked findings (T- items), the attack
sequence and the owner-decision record all closed by 2026-09-05 and moved to
the changelog.
Where the open items live¶
https://github.com/HybridCloudWorks/HCW-HybridCloudWorks/issues
| Label | Meaning |
|---|---|
owner-gated |
Needs the owner: a credential, a console action, or a spend decision |
live-check |
Needs an authorized operator against the deployed estate; several come due only on an external trigger and stay open as standing checklists |
podcast |
Podcast hosting, generation and the podcast pages |
| Item | Issue |
|---|---|
Apply the Copilot code review MCP configuration: Terraform apply, COPILOT_REVIEW_CLIENT_ID, the read-only GitHub App, the settings paste |
#369 |
Podbean feed returns 410; fetchPodcastFeeds fails every 2 hours; Podbean still on the pages |
#348 |
| Replace Podbean: RSS.com hosting, ElevenLabs speech, StreamYard, one audio surface | #349 |
Optional: REPLICATE-API-KEY for AI hero images |
#350 |
Optional: default hero covers, admin_config/default_heroes |
#351 |
Optional: admin_config/social_autopost |
#352 |
Optional: YOUTUBE-API-KEY for Listen & Learn watch-next |
#353 |
Optional: GCP-BILLING-API-KEY for the pricing tool |
#354 |
Live check: Entra role claim, API audience, getCurrentAdminStatus |
#355 |
| Live check: the deployed no-op Labs job path | #356 |
| Live check: public API and custom domain after a DNS or edge change | #357 |
| Live check: third-party webhooks after an approved mutation test | #358 |
| Cosmos recoverability: exporter and a timed restore against RTO 8 h / RPO 24 h | #231 |
createContentFromRecording, the last unimplemented RPC |
#180 |
| Cloudflare Pro and managed WAF rulesets | #127 |
GEMINI-API-KEY already covers Listen & Learn speech; nothing to provide.
Accepted risks¶
A decision to live with a finding rather than fix it. An accepted risk with no record is indistinguishable from an unfixed one: the next reviewer re-raises it, or someone "fixes" it without knowing it was a choice.
| Risk | Accepted | Reasoning, and what compensates |
|---|---|---|
Log-based alerts sleep when the ingestion cap binds. If daily volume ever again reaches the 0.25 GB cap, function_http_5xx and function_response_time stop evaluating from cap-hit until the 08:00 UTC reset — a partial failure in that window surfaces the next morning. Accepted with the T-719 decision |
Owner, 2026-09-02 | A personal content site with RTO 8 h does not need same-hour paging on partial failures. The exposure was daily and unrecorded while host verbosity pinned the cap; after the verbosity cut the cap is headroom and the window should not recur. Compensating controls: the T-519 edge probe pages on unreachability twelve times an hour on a pipeline the cap cannot touch, and logs_daily_cap alerts at 80% of quota before the blindness starts |
Key Vault purge protection is off on kv-site-prod-cus-01, which holds 18 live secrets. Raised as Go-Live blocker B2 on 2026-08-24 |
Owner, 2026-08-24 | Enabling it is a one-way switch: once on it cannot be turned off, a deleted vault can no longer be purged, and its name stays reserved for the retention period — which removes the teardown-and-recreate path a single-environment estate depends on. The secrets are seeded and resolving, so the exposure is not "unprotected during setup". Compensating control: soft delete at 90 days, which still makes an accidental delete recoverable. What is given up is protection against a deliberate purge by someone already holding the rights to perform one. Recorded in the same terms in infra/variables.tf and infra/README.md |
cloudflare_origin_secret is a real shared-secret value in Terraform state. Raised as T-723, 2026-08-28 |
Recorded 2026-08-28 | Unavoidable rather than chosen: Terraform configures the Cloudflare end of the origin handshake, so the value has to pass through it. It was simply never written down, which is the part that is fixed here. Rotation consequence, which is the reason this needs a record: the value must change in three places in one window — the HCP Terraform workspace variable, Key Vault CF-ORIGIN-SECRET, and the Cloudflare transform rule Terraform writes — and a mismatch throws on every anonymous request, so a partial rotation is a full outage of the public API rather than a degradation. The companion exposure — the azapi read-back exporting the whole live app-settings map into state — is not accepted but bounded: it is safe only while every secret-shaped setting is a Key Vault reference, and functions/src/functions/app-settings-secrets.test.js now fails CI if one is not |
Handling rules¶
- Never paste secret values, private keys, access tokens, or personal data into this file, issues, logs, or the Wiki.
- An open item is an issue. This file does not carry work; when something new is found, open an issue and, if it is a decision to live with a finding, record it under Accepted risks here.
- A missing credential is not an engineering task. Record its name, owner, and approved storage location only.
- Historical migration pages and the two archived plans are evidence, not current instructions for restoring Firebase services.
Completed items are removed from this file after the corresponding regular
entry is present in CHANGELOG.md; item numbers are not reused.