fix(ci): hard-fail sweep-cf-orphans on schedule when secrets missing - #2248
Merged
hongmingwang-moleculeai merged 1 commit intoApr 29, 2026
Merged
Conversation
Replace the soft-skip-with-warning behaviour for scheduled runs of the hourly Cloudflare orphan sweeper with an explicit failure when the six required secrets aren't set. Manual workflow_dispatch keeps the soft-skip path so an operator can short-circuit a deliberate rerun without redoing the secrets dance — they accepted the state when they clicked the button. Why: from some-date to 2026-04-28, all six secrets were unset on the repo. Every hourly tick printed a yellow ::warning:: and exited 0, which GitHub registers as "completed/success" — the sweeper was indistinguishable from a healthy janitor with nothing to do. Cloudflare orphans accumulated unobserved to 152/200 (~76% of the zone quota), and only surfaced via a manual audit. The mechanism to catch this kind of regression is to make the workflow loud: red runs prompt investigation, green runs are presumed healthy. Schedule/workflow_run/push paths now print three ::error:: lines naming the missing secrets, the fix, and a one-line reference to this incident, then exit 1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HongmingWang-Rabbit
requested a review
from hongmingwang-moleculeai
as a code owner
April 29, 2026 01:13
This was referenced Apr 29, 2026
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
…aged providers (#2248) MissingKeysModal and ConfigTab both showed credential input fields for MOLECULE_LLM_USAGE_TOKEN when a platform-managed provider was selected. This allowed users to overwrite the provisioner-injected token. Changes: - MissingKeysModal: filter MOLECULE_LLM_USAGE_TOKEN from envVars when the selected provider is platform-managed (mirrors #2245). Memoized with useMemo so the array reference is stable across renders and does not churn the entries useEffect (Researcher review 9318). - ConfigTab: filter the same token from required_env in the ProviderModelSelector onChange handler (mirrors #2245). - Add regression test covering suppression for platform-managed vs BYOK, render-churn guard, and provider-switch behavior. Fixes #2248.
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
…atform-managed providers (#2388) Researcher review RC 9320 found that ConfigTab.tsx still failed the platform-managed-only-token case. At lines 1041-1053, required_env was only rewritten when filteredEnvVars.length > 0 && wasTemplateDriven. If the selected platform-managed provider's only declared env var is MOLECULE_LLM_USAGE_TOKEN, filteredEnvVars becomes [], so the branch omitted { required_env: [] } and left the prior/template-driven required_env in place. Changes: - ConfigTab: update template-driven required_env even when the filtered list is empty (drop the filteredEnvVars.length > 0 guard). - ConfigTab: carry required_env through selectorModels for registry-backed runtimes so wasTemplateDriven can correctly detect template-driven env lists (RegistryModel already had the field on the wire; expose it in the frontend type and map it in selectorModels). - ProviderModelSelector: add required_env?: string[] to RegistryModel interface so the backend field is visible to the canvas. - Add ConfigTab.platform-managed.test.tsx regression for the single-token platform provider case (+ BYOK preservation guard). Fixes #2248.
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
…ntimes/models (#2248 follow-up) Researcher's fail-open audit found that workspace_provision.go (~:647, :680-695, :718-735) swallowed providerRegistry/DeriveProvider errors and returned empty string on failure. Then only stamped provider when derivedProvider != "", so a registry-KNOWN first-party runtime/model could be provisioned PROVIDERLESS → runtime later re-derived the WRONG provider (the moonshot→platform NOT_CONFIGURED class). Changes: - deriveDefaultConfigProvider now returns (string, error) instead of string. - Registry unavailable/load-error → propagated error (fail-closed). - Unknown/federated runtime → preserved pass-through (providerless success). - Known runtime + known model (exact or prefix match) + DeriveProvider error → propagated error (fail-closed). Mirrors llm_billing_mode.go:230-237. - Known runtime + unregistered model (derive miss) → preserved pass-through. - Extracted deriveDefaultConfigProviderFromManifest for unit-testability. - Updated ensureDefaultConfig to return (map[string][]byte, error). - Updated callers in workspace.go and org_import.go to handle errors. - Regression tests: (a) known runtime + known model + DeriveProvider error → blocked; (b) unknown runtime → providerless success; (c) derive miss → providerless success; (d) known model success → provider stamped. Scope: workspace_provision.go + its tests + caller plumbing only. Branch off fresh origin/main.
HongmingWang-Rabbit
pushed a commit
that referenced
this pull request
Jun 12, 2026
… error + add registry-load-fail test (#2248 follow-up) Researcher review RC 9329 on PR #2390 found two blockers: 1. org_import.go swallowed the new fail-closed config-generation error. In createWorkspaceTree, after the workspace DB row/layout/broadcast are already persisted, cfgErr only logged and continued. That left a silent stuck provisioning workspace during org import. Fixed by calling markProvisionFailed before continuing, so the canvas surfaces the failure card immediately. 2. Registry-unavailable/load-error fail-closed path was not covered. Converted providerRegistry from a named function to a variable function (mirrors the resolveInstanceID testability pattern) so tests can swap in a mock. Added TestDeriveProvider_RegistryLoadErrorFailClosed asserting that a registry load error blocks provisioning. Scope still limited to workspace config/provisioning caller plumbing and tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What incident this guards against
Until 2026-04-28, all six secrets (CF_API_TOKEN, CF_ZONE_ID, CP_PROD_ADMIN_TOKEN, CP_STAGING_ADMIN_TOKEN, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) were unset on this repo. Every hourly tick printed a yellow ::warning:: and exited 0 — GitHub Actions reports those runs as
completed/success. The sweeper was indistinguishable from a healthy janitor with nothing to do, while CF orphans accumulated to 152/200 zone records (~76% of the quota gone) under a steady-state leak fixed in a separate PR (controlplane#318).A red CI run prompts investigation. A green CI run is presumed healthy. Anything in between is the failure mode this PR closes.
Schedule-vs-dispatch split
schedule::error::linesworkflow_run(future)push(future)workflow_dispatch::warning::Test plan
python3 -c 'import yaml; yaml.safe_load(open(...))'parses cleanbash -nparses cleanOut of scope
publish-runtime.ymlhas a softer version of the same anti-pattern (silent cascade-skip whenTEMPLATE_DISPATCH_TOKENmissing, but only on push trigger and PyPI publish has already succeeded). Flagged as separate follow-up — call is more nuanced than schedule-driven janitors.🤖 Generated with Claude Code