Commit Graph

199 Commits

Author SHA1 Message Date
61211dba70 fix(keycloak): collision-free canonical domain for live-warm providers; enroll keycloak
canonical_domain() routes any recipe in warm.WARM_DOMAINS (keycloak) to a distinct warm-canon-<recipe>
domain so the data-warm canonical promote can never collide with the live-warm OIDC provider at
warm-keycloak. keycloak WARM_CANONICAL=True (full canonical coverage without risking live SSO).
2026-06-18 01:58:16 +00:00
cd19c1b172 feat(settings): server settings.toml loader + SKIP_CANONICALS_FOR_UPGRADE + release-tag-first no-canonical fallback
Some checks failed
continuous-integration/drone/push Build is failing
- harness/settings.py: stdlib tomllib loader, [upgrade].skip_canonicals_for_upgrade
  (bool, default false), _SCHEMA single-source defaults+validation; graceful on
  absent/malformed (WARN+defaults), warn-and-ignore unknown keys/tables, TypeError on
  wrong type. Path $CCCI_SETTINGS / /etc/cc-ci/settings.toml. + tracked settings.toml.example.
- resolve_upgrade_base: flag true bypasses the canonical lookup -> no-canonical fallback;
  canonical-present path (incl. samever step-back) unchanged when false.
- _no_canonical_base (always-on, §2.C): newest release tag < head (reuse
  warm_reconcile.newest_older_version) -> main-tip -> skip; replaces jump-to-main-tip.
- unit: full resolution matrix + loader tests; 315 unit pass, ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:55:22 +00:00
3595e80d08 claim(M1): per-recipe history sourced from local /var/lib/cc-ci-runs artifacts (full history, not Drone 100-build slice)
Some checks failed
continuous-integration/drone/push Build is failing
history_for() now enumerates run dirs' results.json, groups by recipe, sorts
newest-first by finished timestamp (mixed numeric+named ids — timestamp is the
only correct key), caps at HISTORY_CAP=30, skips malformed/empty/no-recipe dirs.
Overview + badges + /runs + security guards + stdlib-only unchanged.
Local verify: 13/13 unit tests; full-fixture vs 308 real results.json →
bluesky-pds=8 in exact ts order, plausible capped 30 newest, edge dirs skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 16:25:39 +00:00
83c183d985 feat(canon): §2.G strip UPGRADE_BASE_VERSION entirely (plausible verified dynamic-base green)
All checks were successful
continuous-integration/drone/push Build is passing
Gate satisfied — live: with the pin removed, plausible's upgrade tier resolves base 3.0.1+v2.0.0 via
the same-version step-back (canonical 3.1.0 == head 3.1.0 → newest-older = 3.0.1, NOT the broken
3.0.0) and passes install+upgrade green (level 5/5). The pin is redundant, so removed everywhere:
- meta.py KEYS entry (RecipeMeta field auto-drops; 15→14 keys).
- run_recipe_ci.resolve_upgrade_base override branch + docstrings.
- tests/unit/test_meta.py (count 15→14, dropped None-assert), test_upgrade_base.py (override test).
- docs/recipe-customization.md (regenerated table + mentions), docs/testing.md.
- tests/plausible/recipe_meta.py (pin removed), tests/bluesky-pds (re-enable note → dynamic base).
294 unit tests pass; lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:31:53 +00:00
f611dda893 feat(canon): §2.G remove plausible UPGRADE_BASE_VERSION pin (dynamic base resolves 3.0.1 via step-back)
All checks were successful
continuous-integration/drone/push Build is passing
plausible's canonical is established at 3.1.0+v2.0.0 (latest), so the dynamic resolver no longer
needs the explicit pin: a same-version head steps back to newest-older = 3.0.1+v2.0.0 (NOT the
broken 3.0.0). Verifying live before stripping the key globally (§2.G gate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:26:25 +00:00
d072d7e2c2 fix(canon): de-enroll keycloak (live-warm OIDC provider) — §2.B exception
All checks were successful
continuous-integration/drone/push Build is passing
keycloak is the always-on shared OIDC dep provider at warm-keycloak.ci..., the SAME stable domain a
data-warm canonical would use → the sweep's promote would collide with the live provider that
lasuite-*/drone depend on. keycloak is kept current by roll_warm_infra (WC1.1) instead.
WARM_CANONICAL=False; exception recorded in DECISIONS. Enrolled set now 20.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 10:54:14 +00:00
a20890a363 feat(canon): M1.2 release-tag trigger + faithful mirror-sync in the weekly sweep (§2.C/§2.D)
All checks were successful
continuous-integration/drone/push Build is passing
- warm_reconcile.sweep_decision(latest_tag, canon_version): pure new-release-tag trigger
  keyed on version_key (NOT commit) — new tag>canon → run; ==/older → skip no-new-version
  (even with untagged main commits); no tag → skip never-released. Unit-tested.
- scripts/recipe-mirror-sync.sh: faithful mirror sync (adapted from open-recipe-pr.sh
  --reconcile-only) — explicit coopcloud `upstream` remote (robust to inconsistent clone
  remotes), syncs main+TAGS, closes merged-upstream PRs, leaves unrelated PRs, bot-token auth.
- nightly_sweep rewritten: per enrolled recipe → mirror_sync → fetch → sweep_decision →
  run_on_tag (checkout the release tag + CCCI_SKIP_FETCH=1 so head IS the tag → tagged-promote
  gate passes, REF empty → promote allowed). Skips logged; run-twice → skip-all determinism.
- smoke-tested recipe-mirror-sync.sh live on custom-html: faithful no-op main/tags push,
  closed merged-upstream PR #2, left pending PR #5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 06:45:43 +00:00
136100f610 feat(canon): M1.3 enroll all 21 used-recipes as data-warm canonicals (§2.B)
All checks were successful
continuous-integration/drone/push Build is passing
WARM_CANONICAL=True added to every recipe in cc-ci-plan/used-recipes.md (20 weekly +
uptime-kuma external). enrolled_recipes() now returns all 21. Test fixtures
(custom-html-*-bad, concurrency, regression) intentionally left unenrolled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 06:35:30 +00:00
27e06289f8 feat(canon): M1.1 tagged-promote gate — canonical only advances to a published release tag
All checks were successful
continuous-integration/drone/push Build is passing
- should_promote_canonical gains a `tagged` requirement (canon §2.A): a green cold
  latest run promotes only when the tested head version is a published release tag;
  an untagged main commit never becomes a canonical.
- warm_reconcile.is_released_version(recipe, version): release-tag membership (exact or
  by version_key). Caller computes `tagged` so the gate stays pure.
- unit tests: untagged -> no promote; is_released_version cases.
- drive-by (pre-existing reds, unrelated to canon, now green): test_warm_reconcile
  traefik assertion was stale vs the phase-pxgate spec (probes /api/version, no
  health_domain); meta.py UPGRADE_BASE_VERSION KEYS help synced to the prevb doc text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 06:34:09 +00:00
b29bb3f804 feat(samever): step back to older base when last-green canonical == head version
resolve_upgrade_base now reads the head's published version (abra.head_compose_version,
the coop-cloud.<stack>.version label) and, when the last-green warm-canonical version
equals it, steps back to the newest published version strictly older than head instead
of deploying a same-version no-op. warm_reconcile gains version_key + newest_older_version
(single coop-cloud ordering source; sort_versions refactored onto version_key, no behavior
change). Skip only when no older published predecessor exists. Step-back returns kind=version
so it inherits F1d-2 pinned-tag checkout. Extends tests/unit/test_upgrade_base.py (13 pass).
2026-06-17 04:24:14 +00:00
b66abc4978 fix(prevb): discourse custom mint_admin image-agnostic (official /var/www/discourse + DB-password re-export; bitnami fallback)
All checks were successful
continuous-integration/drone/push Build is passing
The custom tier runs on the PR head — now genuinely the official discourse/discourse image (prevb
stopped the overlay reverting it to bitnamilegacy). mint_admin hardcoded /opt/bitnami/discourse (404 on
official) → create-topic roundtrip failed. Detect /var/www/discourse, re-export DISCOURSE_DB_PASSWORD
from /run/secrets (entrypoint exports it only for boot), run bin/rails; keep bitnami fallback.
2026-06-17 01:20:41 +00:00
e1b32ea650 fix(prevb): prune orphan services on upgrade redeploy (head's dropped services); re-add EXPECTED_NA-other-rung test; consume Adversary inbox
All checks were successful
continuous-integration/drone/push Build is passing
docker stack deploy doesn't prune services the head compose dropped (discourse PR#4 drops sidekiq),
leaving them orphaned on the base image. perform_upgrade now reconciles the live stack to the head
compose service set (lifecycle.prune_orphan_services). Makes the deployed stack faithfully reflect
the head — no test weakened. No-op when service sets match / compose unresolvable.
2026-06-17 00:29:00 +00:00
bb2e3c6b2c feat(prevb): dynamic upgrade base (last-green→main→skip) + per-recipe previous/ overlay; migrate discourse off static base + leaky overlay
All checks were successful
continuous-integration/drone/push Build is passing
- resolve_upgrade_base: BasePlan(kind=version|ref|skip); last-green (warm canonical) primary,
  main-tip fallback, declared skip else. UPGRADE_BASE_VERSION retained as optional override.
- deploy_app: base_ref path (chaos-deploy a main-tip/last-green commit) + apply_previous wiring.
- lifecycle: previous/ surface (has_previous, previous_target_version, previous_status decision,
  provide/remove overlay, compose_file add/remove, recipe_branch_commit, stack_service_names).
- generic.perform_upgrade: strip previous/ overlay + COMPOSE_FILE entry before head redeploy.
- discourse: compose.ccci.yml now environmental-only (order: stop-first); removed bitnamilegacy
  pins + sidekiq + UPGRADE_BASE_VERSION; test_upgrade.py asserts head image == official 3.5.3 + no sidekiq.
- unit tests: resolve_upgrade_base matrix + previous/ apply/skip/stale + COMPOSE_FILE layering.
2026-06-17 00:15:06 +00:00
ad53b5a620 fix(gtea): derive STACK_NAME from domain (dots→underscores) in UPGRADE_SECRET_PREP
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
abra does NOT write STACK_NAME to the app's .env file — it derives it at runtime
by replacing dots with underscores (e.g. gite-e1cb78.ci.commoninternet.net →
gite-e1cb78_ci_commoninternet_net). Build #691 failed with 'STACK_NAME not found'
because the env file read was looking for a key that doesn't exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:56:44 +00:00
2d865f06cb fix(gtea): ruff format + check all gtea files and bridge.py
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Clears cc-ci self-test lint failures:
- ruff format: 9 files reformatted (all gtea test files + test_discovery.py)
- ruff check --fix: bridge.py UP017 (datetime.UTC alias) + 6 gtea check errors
- manifest.py B007: rename unused loop variable path → _path (no auto-fix available)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:52:01 +00:00
d832b353e4 fix(gtea): UPGRADE_SECRET_PREP hook — pre-insert lfs_jwt_secret with correct 43-char format
Some checks failed
continuous-integration/drone/push Build is failing
Blocker 4 fix: abra `secret generate --all` uses .env.sample for length hints; the
lfs-plain-gitea PR has SECRET_LFS_JWT_SECRET_VERSION=v1 COMMENTED OUT, so abra produces
a wrong-length secret. gitea requires exactly 43 chars (32 bytes base64 URL-safe); wrong
length → gitea fatals trying to save the JWT secret to the read-only Docker Config
app.ini → health check fails → swarm rolls back.

Fix: new UPGRADE_SECRET_PREP hook (meta.py) called before `abra secret generate --all`
in the upgrade path. abra's `--all` is idempotent (skips existing secrets), so the
correctly pre-inserted secret survives. gitea's recipe_meta.py implements the hook using
`docker secret create` directly to guarantee correct format regardless of .env.sample.

Also consumes machine-docs/BUILDER-INBOX.md (Adversary Blocker 4 digest).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:46:28 +00:00
a121d2c069 fix(gtea): fix M2 blockers — LFS upgrade and REF=main HC1
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is failing
Blocker 1 (LFS roundtrip fails on PR #1):
- Add UPGRADE_EXTRA_ENV to gitea recipe_meta.py — after PR-head checkout
  (compose.lfs.yml now in ABRA_DIR), add compose.lfs.yml to COMPOSE_FILE
  and set SECRET_LFS_JWT_SECRET_VERSION=v1 so the upgrade chaos redeploy
  actually runs with LFS enabled. Without this, the base install checks out
  the 3.5.x tag (compose.lfs.yml removed), EXTRA_ENV sees no LFS, and the
  upgrade chaos redeploy inherits the no-LFS .env — so the LFS test runs
  (compose.lfs.yml is restored by recipe_checkout_ref) but LFS is off.
- Add abra.secret_generate(domain) in generic.perform_upgrade when
  upgrade_env is non-empty — generates lfs_jwt_secret before chaos redeploy.

Blocker 2 (REF=main upgrade fails HC1):
- Always use recipe_head_commit (git rev-parse HEAD) for head_ref instead
  of using ref directly. When ref="main" (a branch name), the HC1 commit
  check "head_ref.startswith(chaos_commit)" always fails since "main" ≠ SHA.
  recipe_head_commit returns the actual SHA after the fetch/checkout.

Side-fix (stale creds — build #675):
- ops.py pre_install: delete the per-domain creds file before calling
  _ensure_admin. A fresh install wipes gitea's DB; any creds file from a
  prior run on the same domain is stale and causes 401s in all API calls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 21:01:21 +00:00
74bc5f0106 fix(gtea): test_admin_api: add token scopes for gitea 1.22+
Some checks failed
continuous-integration/drone/push Build is failing
Gitea 1.22+ (including 1.24.2 on cc-ci) requires explicit scopes
when creating API tokens. Add read:user + read:organization to satisfy
the token creation endpoint and the read-back assertions that follow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:06:42 +00:00
3cc8338a78 fix(gtea): test_git_push: auto_init repo + direct URL push
Some checks failed
continuous-integration/drone/push Build is failing
Empty-repo HTTPS push with git clone exits 0 but silently fails (remote
branch creation on an empty clone is unreliable). Fix:
- Create repo with auto_init=True + default_branch=main (initial commit present)
- Clone into a non-existing subdir (git clone must target non-existing path)
- Push via explicit cred_url (bypasses remote config; no tracking needed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:04:48 +00:00
893a7b0eb4 fix(gtea): embed git credentials in URL; fix double /api/v1 path; add git-lfs
Some checks failed
continuous-integration/drone/push Build is failing
- test_git_push.py + test_lfs_roundtrip.py: use cred_url (https://user:pass@host/...)
  instead of GIT_CONFIG_COUNT insteadOf rewriting, which silently failed to
  propagate credentials to the push step (repo remained empty after push exit 0).
  Also add GIT_SSL_NO_VERIFY=true and GIT_TERMINAL_PROMPT=0.
- test_lfs_roundtrip.py: fix restart health-poll path /api/v1/version → /version
  (_api() already prepends /api/v1; double prefix produced 404 and a 120s timeout).
- nix/hosts/cc-ci/configuration.nix: add git-lfs to systemPackages (required for
  the LFS capstone test on the lfs-plain-gitea PR branch).

Adversary pre-M1 findings: Issue 1 (git-lfs absent) + Issue 2 (double path) both fixed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:01:31 +00:00
6ac9989140 fix(gtea): wait for visible input#user_name on gitea login page
Some checks failed
continuous-integration/drone/push Build is failing
_csrf is a hidden field; wait_for_selector defaults to state=visible
and times out. Switch to the visible username input which proves the
login form rendered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:56:25 +00:00
33561c8609 feat(gtea): build full gitea test suite (M1 build — all files)
Some checks failed
continuous-integration/drone/push Build is failing
- tests/gitea/recipe_meta.py: updated from dep-provider stub to dual-role (dep + recipe-under-test).
  Adds BACKUP_CAPABLE=True, READY_PROBE (/api/v1/version), SCREENSHOT (sign-in page), LFS-
  conditional EXTRA_ENV (compose.lfs.yml + GITEA_LFS_START_SERVER only when RECIPE=gitea AND
  overlay present — dep path unchanged). All existing dep keys preserved; 10/10 dep unit tests pass.

- tests/gitea/ops.py: NEW — admin user creation via gitea CLI (ci_admin, creds in /tmp per-domain
  file), marker repo lifecycle (pre_install/pre_upgrade/pre_backup create; pre_restore deletes to
  diverge from backup state).

- tests/gitea/test_{install,upgrade,backup,restore}.py: NEW — lifecycle overlays. Install checks
  API + admin auth + Playwright sign-in. Upgrade/backup/restore assert marker repo continuity.

- tests/gitea/custom/: NEW — test_health.py (parity: HTTP 200 root), test_git_push.py (parity:
  create→clone→push→verify→delete), test_admin_api.py (beyond-parity: user+org+token CRUD),
  test_lfs_roundtrip.py (LFS OID round-trip + JWT stability; skips on main, runs on PR #1 head).

- tests/gitea/PARITY.md: NEW — mapping table, source note (recipe-info corpus not upstream repo),
  beyond-parity rationale, backup/restore real-tier note, DB choice, dep-split mechanism, LFS skip.

- machine-docs/STATUS-gtea.md: NEW — phase status (building M1).
- machine-docs/BACKLOG-gtea.md: merged with Adversary init.
- machine-docs/JOURNAL-gtea.md: Builder log with design decisions + unit test results.
- machine-docs/REVIEW-gtea.md: kept Adversary init content.
- machine-docs/DECISIONS.md: appended gtea section (LFS split, admin mgmt, marker design).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 19:50:08 +00:00
d44f799de9 fix(cfold): wait for ghost db in entrypoint
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2026-06-13 03:58:59 +00:00
ee6b613ff3 fix(cfold): delay ghost app retry during db crossover
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is failing
2026-06-13 02:18:17 +00:00
23f1861b7a fix(bridge): ignore pre-start trigger comments
Some checks failed
continuous-integration/drone/push Build is failing
2026-06-13 00:27:22 +00:00
44e02425ab feat(cfold): canonicalize custom test layout
Some checks failed
continuous-integration/drone/push Build is failing
2026-06-12 16:08:18 +00:00
1be74fb9e1 fix(lint): F821 undefined 'e' in test_scm_configured; shfmt/ruff auto-fixes
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
- test_scm_configured.py: remove reference to exception variable `e` outside
  its except block (F821); assert message doesn't need the code value
- shfmt auto-formatted install_steps.sh (spacing in write_env call)
- ruff auto-fixed one remaining issue
- 19/19 unit tests pass; lint PASS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:17:19 +00:00
0aa46dbe72 fix(drone-dep): ADV-drone-02 — teardown fallback when SSO enrichment fails after deploy
Some checks failed
continuous-integration/drone/push Build is failing
When _enrich_deps_with_sso raises after deploy_deps succeeds (e.g., gitea API
call fails), deps_state stays {} and the finally block's `if deps_state:` guard
skips teardown, orphaning the dep at its deterministic domain.

Fix: add an `else` branch after the `if deps_state:` block that reads
$CCCI_DEPS_FILE (the legacy-list written by deploy_deps) and calls
teardown_deps on the cold entries so no dep is left running.

Unit tests: test_load_run_state_provides_fallback_for_enrichment_failure and
test_fallback_skips_warm_entries verify the data-flow that the fallback relies on.
19/19 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 22:03:29 +00:00
7e7e84df34 fix(drone): ADV-drone-01 — no-follow redirect pattern in SCM test
Some checks failed
continuous-integration/drone/push Build is failing
test_scm_configured.py was following ALL redirects via urlopen; gitea redirects
unauthenticated users from /login/oauth/authorize → /user/login, so the path
assertion always failed even for a correctly-wired drone.

Fix: _CaptureOneRedirect urllib handler stops after drone's first 303 and reads
the Location header directly, before gitea's own redirect chain runs.

- Consume BUILDER-INBOX.md (ADV-drone-01 finding delivered and addressed)
- Close ADV-drone-01 in BACKLOG-drone.md
- Update test_gitea_dep.py terminology: "location_url" not "final_url"
- All 10 unit tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:48:36 +00:00
51c3280163 feat(drone): enroll drone + gitea SCM dep (M1 implementation)
Some checks failed
continuous-integration/drone/push Build is failing
- tests/gitea/recipe_meta.py: gitea as install-time dep provider; sqlite3
  overlay EXTRA_ENV, health path /api/healthz, relaxed access for CI use
- tests/drone/recipe_meta.py: DEPS=["gitea"]; health /healthz; 600s timeout
- tests/drone/install_steps.sh: wires GITEA_CLIENT_ID + GITEA_DOMAIN +
  client_secret Docker secret + DRONE_USER_CREATE before single drone deploy
- tests/drone/functional/test_scm_configured.py: Playwright-free SCM test —
  follows /login redirect, asserts final URL is gitea dep's OAuth2 authorize
  endpoint with matching client_id (per Adversary pre-probe REVIEW-drone.md)
- tests/drone/PARITY.md: backup structural-skip justified (no backupbot labels)
- runner/harness/sso.py: setup_gitea_oauth() — creates gitea admin user via
  CLI + OAuth2 app via API, returns {admin_user, admin_password, client_id,
  client_secret} for install_steps.sh consumption
- runner/run_recipe_ci.py: _enrich_deps_with_sso now handles gitea dep (calls
  setup_gitea_oauth; keycloak path unchanged)
- tests/unit/test_gitea_dep.py: unit tests for gitea dep path — meta loading,
  SSO routing, SCM redirect assertion logic (parametrized)
- machine-docs: STATUS/JOURNAL/BACKLOG-drone.md phase state files initialized

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 21:31:43 +00:00
b17b6f1232 claim(mailu): M2 — DEFERRED closed; PARITY.md updated with dual-volume evidence; operator summary written; PR#3 open for merge; awaiting Adversary fresh re-trigger
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2026-06-11 21:03:51 +00:00
b9352e8313 fix(mailu): extend backup/restore seed to cover /mail Maildir volume (ADV-mailu-01)
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2026-06-11 20:56:00 +00:00
1fbc4e0b15 fix(mailu): fix _mailu import path in ops.py+overlays (functional/ subdir)
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2026-06-11 20:44:40 +00:00
4b5051f003 feat(mailu): add ops.py + backup/restore tests + update PARITY.md (P4 now covered via PR#3)
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is failing
2026-06-11 20:41:33 +00:00
9afdf3de5a claim(kuma): M2 — build #462 LEVEL 5 PASS (flake #2); DEFERRED closed; PARITY updated
Some checks failed
continuous-integration/drone/push Build is failing
Second drone run #462: uptime-kuma@eb4521cc (PR #3) = LEVEL 5.
test_monitor_wizard [pass] in both #460 + #462 — flake check complete.
DEFERRED.md "uptime-kuma create-a-monitor" closed with build+commit pointers.
PARITY.md: new row for tests/uptime-kuma/playwright/test_monitor_wizard.py.
M1 Adversary PASS @2026-06-11T18:26Z (REVIEW-kuma.md).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 18:32:16 +00:00
8da59cff22 feat(kuma): implement wizard+monitor Playwright test (tests/uptime-kuma/playwright/)
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
Phase kuma M1 impl: resolves the 2026-05-28 DEFERRED uptime-kuma create-a-monitor item.

Approach: Playwright (option b) — python-socketio not in cc-ci Nix env; Playwright
handles Socket.IO transparently via the real browser. Selectors confirmed in 2.2.1
compiled bundle (data-cy setup wizard + data-testid monitor form/status badge).

Test flow (test_monitor_wizard_and_probe):
1. Setup wizard: admin create via data-cy form → auto-login → /dashboard
2. Create self-probe monitor (https://{live_app}/) → wait ≤90s for "Up" badge
3. Heartbeat table row check: isFirstBeat=important, row has real datetime stamp
4. Negative: dead-port monitor (http://127.0.0.1:19999/dead) → wait ≤60s for "Down"

All waits are bounded poll with page.wait_for_function/wait_for_url/wait_for_selector.
Admin password: 64-char UUID hex, never printed/logged.

Also: DECISIONS.md records Playwright choice; phase state files bootstrapped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 18:15:13 +00:00
0cc31a507e fix(dstamp): discourse upgrade stop-first overlay (stop 2x-memory start-first OOM→spurious swarm rollback) + harness assert_upgrade_converged (detect rollback/pause → honest upgrade failure, HC1 unweakened). Root cause: failure_action:rollback reverted chaos-version label, masked by start-first+wait_healthy
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 17:07:38 +00:00
e9745c8c74 feat(bsky): EXPECTED_NA['upgrade'] suppresses the upgrade-tier base deploy — single deploy = PR head; bluesky-pds declares it (no deployable base: every published tag pins the republished moving :0.4). upgrade_base() extracted pure + 6 unit tests; meta-key doc regenerated. 253 unit tests + repo lint PASS
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2026-06-11 11:51:12 +00:00
68c3486216 fix(lvl5): lint executor PR-path — abra lint selects+checks out the repo DEFAULT BRANCH; scratch clone of a detached per-run tree has none (FATA, live 400-402), and a stale default would be silently linted instead of the PR head. Force local main AT the tested ref + repoint origin to the scratch itself (offline tag fetch, no drift). Regression test with detached two-commit source proves exact-ref content is linted. 247 unit tests green; real-abra detached-source smoke pass.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2026-06-11 10:56:56 +00:00
1d3b61c6c2 fix(lvl5): lint table parser — abra renders HEAVY box verticals (┃ U+2503); accept both; meta registry EXPECTED_NA/BACKUP_CAPABLE wording → regenerated doc table
Some checks failed
continuous-integration/drone/push Build is failing
Found by real-abra smoke on cc-ci: hedgedoc clean → pass; +lightweight tag →
fail R014. Full suite 246 passed on cc-ci venv.
2026-06-11 07:49:29 +00:00
e219a7891d feat(lvl5): P1 — 5-rung ladder (L5=abra recipe lint) + de-capped level semantics
All checks were successful
continuous-integration/drone/push Build is passing
level.py: RUNGS += lint; statuses {pass,fail,skip,unver}; compute_level = max passed
rung with all below pass-or-skip (fail/unver block); cap_reason/capped DELETED.
harness/lint.py: lint executor — pristine scratch clone of the per-run tree at the
exact tested ref (mirror-origin + untracked-overlay pollution solved by context, no
rule filtered), PTY via script -qec, 60s hard budget, lint.txt artifact, table-parse
classifier (rc only signals FATA), unver on any non-run (never silent pass).
results.py: derive_rungs classifies every N/A source (structural/declared → skip,
else unver), lint rung + synthetic lint stage + lint block in results.json, schema 2,
cap fields removed. run_recipe_ci.py: lint call before tiers (double-wrapped,
verdict-neutral), badge = level only. card/dashboard: 0-5 ramp, cap line → 'level N
of {4|5}', unverified rows, badge number+colour only, lint.txt servable, old schema-1
artifacts render untouched. Unit suite rewritten: 245 passed on cc-ci venv.
2026-06-11 07:42:30 +00:00
3c33129ebd fix(shot): mattermost hook v2 — interstitial appears on ANY first-visit route incl /login (proven byte-identical PNG); click 'View in Browser' best-effort then settle; unit test covers click + no-interstitial fallback; 207 pass, lint PASS
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 06:45:43 +00:00
7ad7d1f20d fix(shot): A1 — blank-retry keeps the LARGER frame (retry snapped to temp path, os.replace only if >= first; worse late frame discarded + temp cleaned); regression test [9999,4801]->9999; 207 unit tests pass, lint PASS
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 06:24:01 +00:00
80e5713c5c feat(shot): mattermost-lts SCREENSHOT hook → /login (default lands the desktop-or-browser interstitial; watch-list wants the real sign-in form) + public screenshot.settle() for hooks; unit test via real loader; 206 unit tests pass, lint PASS
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 06:19:39 +00:00
b98a471dac fix(shot): plausible SECRET_KEY_BASE 62→68 chars — Phoenix cookie store requires >=64 bytes, so EVERY HTML render 500'd (the real cause of screenshot:null on all runs; /api/* unaffected which is why tiers passed). Default capture now lands the real registration page; verified: shot-fix-plausible run install=pass, screenshot.png 64132B real form, no hook needed
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2026-06-11 05:55:43 +00:00
ce50f641cc feat(shot): harness default capture fix — bounded networkidle settle after domcontentloaded + blank-frame retry (≤60s wait budget, R7 best-effort preserved); 6 unit tests; lint PASS, 205 unit tests pass via cc-ci-run
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 01:31:03 +00:00
be2026aafb fix(harness): services_converged — a replica deficit explained entirely by Complete tasks is converged (triggered one-shot, rcust M2 lasuite-drive root cause)
All checks were successful
continuous-integration/drone/push Build is passing
2026-06-11 00:26:53 +00:00
1357544301 fix(tests): restore best-effort semantics of lasuite-drive pre_install bucket trigger (rcust M2 regression)
All checks were successful
continuous-integration/drone/push Build is passing
The P2b port of setup_custom_tests.sh -> ops.py::pre_install made the 90s bucket-poll timeout a
fatal AssertionError; the original shell hook fell through on timeout BY DESIGN (best-effort) and
the custom-tier MinIO storage test is the real gate for a genuinely missing bucket. Live evidence:
in both M2 sweep failures the bucket landed just after the window and every later tier including
the custom MinIO test passed. Warn loudly + continue, exactly the old semantics.

Adversary-approved fix-forward (REVIEW-rcust 57c66ad, scoped to this raise).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:53:31 +00:00
858e0f582f fix(harness): redact secret-named meta values in the customization manifest (rcust)
All checks were successful
continuous-integration/drone/push Build is passing
Adversary heads-up (inbox 2026-06-10T19:06Z): meta values are repo-public by construction, but
the manifest lands on the dashboard — a field literally named SECRET_KEY_BASE showing a value
(plausible's committed CI dummy) is needless secret-scan noise. Mask values whose key NAME is
secret-shaped (SECRET|PASSWORD|TOKEN|CREDENTIAL|word-segment KEY), top-level and nested dict
keys; the key name stays visible. Unit test pins redacted vs passthrough (KEYCLOAK_URL).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 19:09:09 +00:00
68954be53e feat(harness): P5 — customization manifest (rcust)
All checks were successful
continuous-integration/drone/push Build is passing
One block at run start answering "what does this recipe customize?" across every surface
(non-default recipe_meta keys, ops.py pre-ops, install_steps.sh, compose.ccci.yml, lifecycle
overlays by source, custom-test counts, active CCCI_SKIP_GENERIC* env overrides — !!-flagged when
riding a CI run, P2c), printed to the run log and embedded verbatim in results.json under
"customization". Pure presentation — building/printing it never influences a verdict; the
manifest honors the HC2 repo-local gate so it never advertises code the run will not execute.

Unit tests: synthetic recipe exercising every surface -> complete + deterministic + JSON-clean;
HC2 invisibility; env-override flagging; render golden lines; build_results threads the dict
verbatim (key always present, None when absent).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 18:57:26 +00:00