Commit Graph

153 Commits

Author SHA1 Message Date
Kit OC5
8ebc18c3bc gitea 1.24.6 -> 1.24.7 (security: LFS auth bypass, symlink bypass, OAuth2 missed return)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 02:45:28 -04:00
Kit OC5
9566826ce9 lockbox-put: append-only lockbox PR tool (no one reads/greps the lockbox); installer updated
All checks were successful
check / gate (push) Successful in 28s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 02:40:31 -04:00
Kit OC5
160a3d69ba backup_state.sh: encrypted restic backup of Postgres + Gitea state to R2 (SOTU 10-01 gap: DB was not backed up)
All checks were successful
check / gate (push) Successful in 23s
canary / probe (push) Successful in 6s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 02:35:09 -04:00
Kit OC5
7e28a23c22 secret-scan + env-names: shared hash-only tools (Boss 10-01: lanes printed secrets while hunting them)
All checks were successful
check / gate (push) Successful in 9s
canary / probe (push) Successful in 5s
secret-scan reports file:line/commit + lockbox KEY NAME or shape, never a value or fragment;
env-names lists variable names/length/hash only. Same shapes as secret-guard. Seeded-fake tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 01:17:30 -04:00
Kit OC5
1da4d39c0b bridge + sync: onboard windy-text, windy-call, windy-cell (telephony in scope, GitHub Actions dead since 08-14; deploy.yml disabled)
All checks were successful
check / gate (push) Successful in 14s
canary / probe (push) Successful in 6s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 01:00:48 -04:00
Kit OC5
53fbcfe78f secret-guard allow: windy-code VS Code public aiKey, windytalk redaction fixture (hash not in lockbox)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 00:59:59 -04:00
Kit OC5
1c552e94de secret-guard: Twilio shapes (SID/API key, 32-hex secret assignment) + per-kind warn mode
Windy Text 10-01: a live Twilio auth token sat in bridged-repo tests. Auth tokens are bare
32-hex, so they are matched only when assigned to a name containing token/secret/key/password;
hash is of the value alone. SECRET_GUARD_WARN_KINDS lets a new shape warn before it blocks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 00:59:05 -04:00
Kit OC5
8690c4f8d3 secret-guard allow: 5 windy-agent #395 FAKE fixtures (weekly scan 09-28; verified never in the lockbox)
All checks were successful
check / gate (push) Successful in 17s
canary / probe (push) Successful in 5s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 06:13:22 -04:00
Kit OC5
313f41b49c deploy: secret-guard BLOCK drop-in (orchestrator 09-24)
All checks were successful
check / gate (push) Successful in 8s
canary / probe (push) Successful in 6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:08:11 -04:00
Kit OC5
ea02ade0cb weekly public secret scan (all 5 GitHub accounts, full history, hash-only)
All checks were successful
check / gate (push) Successful in 13s
canary / probe (push) Successful in 4s
scripts/public_secret_scan.py: every PUBLIC repo, every object (incl.
unreachable + PR refs), secret_shapes patterns, excused by the secret-guard
allow list. Output JSON with hash8 + location only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:05:16 -04:00
Kit OC5
497222094f secret-guard: triaged allow list (fakes by hash, test PEMs by path)
Private-key matches are only the BEGIN line (same hash everywhere), so they
are allowed by path+kind; everything else by hash. Real revoked tokens
(1354fc9b, d49dc2ba) are pinned by a test to never be allowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:04:13 -04:00
Kit OC5
d28da26000 secret-guard: no live credentials in bridged repos (hash-only findings)
All checks were successful
check / gate (push) Successful in 22s
New guard windy-git/secret-guard (warn-only) over EVERY text file: Telegram,
GitHub, AWS, Slack, Anthropic, OpenAI, Stripe live, Google API keys and
private-key blocks (scripts/secret_shapes.py, shared with the weekly public
scan). A finding carries "<kind> #<sha256[:8]>", never the value (house rule
10). Known fakes allowed BY HASH (ci/secret-guard-allow.yml). GUARDS_STATUS
gets a secrets column. Leak hunt 09-24: @Windy_0_bot token in a public fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 03:01:59 -04:00
Kit OC5
04c857654a rerun_ci.sh: find wg-q in the invoking user home under sudo
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 5s
Under sudo ~ is /root, so the final run listing failed (windy-inbox #14).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 02:38:25 -04:00
Kit OC5
32512a32fc bridge windy-inbox (new private repo; Windy Drops is build lead)
All checks were successful
check / gate (push) Successful in 17s
canary / probe (push) Successful in 4s
sync REPOS + BRIDGE_REPOS + guards page (owner Windy Drops). Imported
writable into Gitea first (repo 164).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:51:09 -04:00
Kit OC5
b52e6b4784 bridge: post no-Docker smoke jobs (name regex skipped "no Docker")
All checks were successful
check / gate (push) Successful in 9s
canary / probe (push) Successful in 5s
windy-search #96 "Boot smoke (no Docker)" passed but was hidden by the
image-build name filter. Negative lookbehind for no/no-/without.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:11:55 -04:00
Kit OC5
6440c7d5f4 deploy: compute-guard BLOCK drop-in (live on Veron since 09-24 00:0xZ)
All checks were successful
check / gate (push) Successful in 12s
canary / probe (push) Successful in 7s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:05:34 -04:00
Kit OC5
17acae6af6 guards: Grant-owned findings never block (compute-guard + ci-hygiene)
status_for(lane, whole_tree, grant=...): only lane-owned findings fail in
MODE=block; Grant-owned (ci/grant-owned.yml) post WARN. The bridge splits via
guards_report.split_grant; if the split cannot run it WARNs (never blocks).
Orchestrator 09-23: block compute-guard for lane-owned paths only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 20:04:01 -04:00
Kit OC5
790d794900 bridge: drop eternitas ci/build from BRIDGE_NO_DAEMON (converted to ci/smoke, #179)
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:51:26 -04:00
Kit OC5
1b8cebbfe1 branding: friendly invite-only page instead of Gitea's raw Registration is disabled
A Windy account with no forge account (registration CLOSED at launch, Grant
09-23) lands on /user/link_account. Override shows invite-only + signed-in name
+ link to the dashboard; other cases = Gitea 1.24.6 template verbatim. No change
to who can register. Orchestrator ask 09-23.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:49:34 -04:00
Kit OC5
83fbf1f992 guards_report: chat lane is now the Windy Chat session
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 6s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:12:40 -04:00
Kit OC5
9b5334fee7 test: allow-list entries must be line-scoped (replaces is-empty check)
f71a5aa pushed with this test red (tail hid pytest rc); fixed here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:11:53 -04:00
Kit OC5
f71a5aab39 ci-hygiene allow: windy-pro disabled deploy job (needs-docker false positive)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:11:20 -04:00
Kit OC5
f219437282 ci-hygiene report: same disabled-workflow filter as check()
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:10:35 -04:00
Kit OC5
b15584d33a ci-hygiene: needs-docker skips workflows disabled on Windy Git
deploy/release workflows run on the target host (real daemon) and are
disabled here (repo_unit DisabledWorkflows); one bounded query per process,
flag everything if it fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:10:11 -04:00
Kit OC5
0a57d96f2e bridge + ci-hygiene: Docker-needing CI jobs (option A)
- bridge: BRIDGE_NO_DAEMON names image-build jobs whose name lacks docker
  (default eternitas:ci/build); never posted, like the docker-named ones.
- ci-hygiene: flag docker build/buildx/run/compose, docker-compose and
  docker/build-push-action in workflow steps ("needs docker") with the fix:
  job services: + a no-Docker smoke test; the image builds at deploy.
- test_guards_report: owner column (14ed23a broke it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:09:09 -04:00
Kit OC5
8b1ae4ac60 branding: home page says invite only (forge registration closed at launch)
Some checks failed
check / gate (push) Failing after 7s
canary / probe (push) Successful in 5s
Site-honesty re-audit 3.17 (Traveler): the home page promised sign-in with any
Windy account while ENABLE_AUTO_REGISTRATION=false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:02:55 -04:00
Kit OC5
14ed23a9fe guards_report: owner-lane column (session names: 8c -> Windy Hub, calendar -> Windy Calender)
Some checks failed
check / gate (push) Failing after 10s
canary / probe (push) Failing after 1m5s
Orchestrator routing 09-23: hub/account-server/dashboard/site -> Windy Hub;
windy-calendar only -> Windy Calender; telemetry -> Windy Admin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 18:44:11 -04:00
Kit OC5
c4799dcc13 ci: mount windy-pro's read-only build inputs into dind; allow exactly that path for jobs
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 5s
Non-secret inputs git-ignored in windy-pro (models, linux-x64 portable
bundle, enter-monitor build) that build-desktop needs. Mounted :ro into
dind; valid_volumes allows only /ci-inputs/windy-pro; refresh-ci-inputs.sh
copies them from the frozen release clone (read-only on the source).
Invariant I-5 narrowed, not dropped: exactly that one path, read-only in
dind, no other service mounts it, still no docker socket (proven to fail
on :rw). Orchestrator-approved (option a). Applied in an idle window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 17:28:48 -04:00
Kit OC5
683c01ec7d rerun_ci: Gitea stores repos lowercased on disk (WindyCloud failed)
All checks were successful
check / gate (push) Successful in 13s
canary / probe (push) Successful in 5s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 17:22:17 -04:00
Kit OC5
4bb4893131 bridge: replace the mirror PR when a GitHub PR is retargeted to another base
All checks were successful
check / gate (push) Successful in 8s
canary / probe (push) Successful in 5s
The mirror kept its creation-time base forever. eternitas #167 was stacked
on fix/one-hallway, retargeted to main after #166 merged; ci.yml
(pull_request: branches [main]) then silently never ran for it, while
unfiltered workflows did. An edited event triggers nothing, so close the
stale mirror and open a fresh one on the new base (runs CI at once).
An unknown base is left alone, never guessed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 16:16:15 -04:00
Kit OC5
9e9eb08d96 compute guard: line-scoped allow entries; allow MindKeychain.jsx's two OAuth endpoints only
All checks were successful
check / gate (push) Successful in 12s
canary / probe (push) Successful in 4s
Allow entries may carry matches: (regexes); then only matching lines are
allowed, so an allowed file can't smuggle in a new call. windy-pro #609
MindKeychain.jsx: openrouter.ai/auth? and /api/v1/auth/keys (BYOK key
acquisition via OAuth PKCE, no inference; successor of the MindPanel
allow, ADR-064). An inference call in the same file still flags (tested).
Orchestrator-approved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:46:53 -04:00
Kit OC5
dece301bf0 grant-owned: windy-pro ROOT .env.example (desktop BYOK dev fallback; hub reads neither)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:45:33 -04:00
Kit OC5
87dcddb87d guards_report: one live status page for compute-guard + ci-hygiene
All checks were successful
check / gate (push) Successful in 15s
Scans every bridged default branch with both guards; lane-owned vs
Grant-owned (ci/grant-owned.yml: windy-pro desktop paths + its desktop CI
jobs, attributed per job) so Grant's code never holds up a block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:38:21 -04:00
Kit OC5
a5f7b036a8 guards: skip a commit the sync hasn't fetched yet, quietly (race, not error)
All checks were successful
check / gate (push) Successful in 15s
canary / probe (push) Successful in 4s
The bridge reads PR/default heads from GitHub after the sync's fetch; a
push in between isn't in the clone until the next cycle. Both guards logged
a CalledProcessError for it (windy-pro main 40 s after the fetch). Now
None = nothing posted this cycle; the next one scans it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:36:19 -04:00
Kit OC5
255aa58b35 ci-hygiene guard: lockfile-only installs, pinned images, no host-port services (warn-only)
All checks were successful
check / gate (push) Successful in 19s
House rule 6 (09-23). The bridge now also posts windy-git/ci-hygiene on
every PR head (added lines) and default branch (whole files), scanning CI
workflows and Dockerfiles for: floating pip / uv pip installs (not -r,
not --no-deps, not exact pins), uv sync without --locked/--frozen,
npm install instead of npm ci (unless every package is exact-pinned),
yarn/pnpm without a frozen lockfile, :latest images and COPY lock* globs
(Windy Mail #147), and CI services publishing a HOST port (every job
shares one dind: Windy Mind runs 147/176 died on 5432). Warn-only;
CI_HYGIENE_MODE=block later. Allow-list ci/ci-hygiene-allow.yml (empty).

compute_guard's walker is now parameterised (line_fn / path_ok /
prefilter) so both guards share one scanner, cache and allow loader; the
bridge posts both through one _post_guard. Today: 95 issues in 21 repos;
windy-git, calendar, traveler, traveler-site clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:30:51 -04:00
Kit OC5
e64a1b5fcb deps: install from uv.lock (hash-pinned) in the image and CI, never floating
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 5s
The API image did 'pip install -e .' and CI 'pip install -e ".[dev]"':
every rebuild could ship newer fastapi/starlette/pydantic than CI tested
(Windy Cloud hit exactly this 09-23). uv.lock is cut to EXACTLY what prod
runs now (42 runtime pkgs, 0 differences; botocore/pyjwt held back to
prod's versions). Image: uv 0.12.5 exports, pip --require-hashes installs,
same layout. CI: uv sync --locked (also fails on a stale lock).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:25:18 -04:00
Kit OC5
1bc55eaec9 compute guard: flag direct AI-provider use (Windy Mind is the only door), warn-only
All checks were successful
check / gate (push) Successful in 28s
canary / probe (push) Successful in 14s
Grant's rule (09-23): every model call goes through Windy Mind. The bridge
now posts windy-git/compute-guard on every PR head (lines the PR ADDS vs its
merge-base) and default-branch head (whole tree): provider hosts, provider
SDK imports/deps and raw provider key names. Warn-only: success + "⚠ WARN"
and a link to the first hit; COMPUTE_GUARD_MODE=block turns it red later.

Exceptions live in ci/compute-guard-allow.yml, each with a reason (Mind
itself, user-BYOK windy-agent / windy-code extension / windy-pro desktop +
MindPanel, windy-connect config writers). Tests, docs, comments, lockfiles,
vendored code and CI config are never scanned. Reads the sync's bare clones
(no docker exec); cached per (repo, sha, rules). Non-fatal; never a fake OK.

First cases = COMPUTE_BYPASS_AUDIT.md. Today on default branches: 38
findings in 3 repos (windy-chat audit #2, windy-pro account-server #3/#4,
windytalk reference/), 0 elsewhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:42:10 -04:00
Kit OC5
fdb0f5989e ci: run dind under Sysbox, not privileged (rollback override kept)
Some checks failed
canary / probe (push) Has been cancelled
check / gate (push) Has been cancelled
dind was privileged: true, so a job that escaped into dind was root on
Veron 1, which is Grant's workstation. Under sysbox-runc (sysbox-ce 0.7.1,
installed 09-23 with no docker restart) dind root is an unprivileged host
uid. Smoke-tested standalone: nested containers, internet, a services-style
postgres on a private network and a python image all pass unprivileged.
Fresh volume dind-storage-sysbox; the old dind-storage stays for
docker-compose.privileged.yml, the one-command rollback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:23:55 -04:00
Kit OC5
9be2952ff8 rerun_ci: detect a running oneshot sync correctly (is-active lies for oneshot)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:22:59 -04:00
Kit OC5
fe3bce39ff bridge: post pending for queued jobs a runner can take
All checks were successful
check / gate (push) Successful in 28s
Gitea 1.24 lists only picked-up jobs, so a queued PR showed NOTHING on
GitHub and lanes asked whether their push was lost (Windy Mind #131,
Windy Cloud today). The bridge now reads waiting jobs from the gitea DB
and posts pending where nothing newer was picked up; a queued re-run
supersedes the stale failure it replaces.

Only status 5 jobs whose runs-on labels a live runner has: blocked jobs
often end skipped and label-unrunnable jobs are cancelled unpicked, and
neither ever reaches /actions/tasks, so their pending would never resolve.
Lookup is bounded (30 s) and non-fatal: the IO-stall lesson.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:20:32 -04:00
Kit OC5
6b0b60eb4a scripts: rerun_ci.sh — re-fire a PR's CI without the web button
Gitea 1.24 has no rerun API and the web button needs Grant's SSO identity.
Guarded branch rewind that the next sync undoes; restores the branch itself
on timeout. Used today for eternitas #166 and windy-mind #131 after the
Veron IO stall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:17:10 -04:00
Kit OC5
60708dd8db push velocity: correlate the SSO-id subquery on the grouped column
All checks were successful
check / gate (push) Successful in 21s
canary / probe (push) Successful in 9s
Dry-run against the real gitea DB: 'subquery uses ungrouped column u.id'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:06:27 -04:00
Kit OC5
aedc772d29 push velocity: isolate its query so a failure never costs ci.run rows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:06:27 -04:00
Kit OC5
acb8ec3a16 push velocity: key humans on windy_identity_id (SSO link); no id -> system + caller
Telemetry UPDATE 2 actor rule: agent/human rows without actor_id are
quarantined. Forge humans sign in only via Windy SSO, so Gitea's
external_login_user.external_id is their windy_identity_id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:06:27 -04:00
Kit OC5
0051c72037 telemetry: detect push velocity from Gitea's action table (alert only)
git push never touches our API, so throttle.py can't see it. Gitea's
action table records every push; the 5-min sync-side emitter now reads
it and emits forge.push_velocity when an account crosses 60 pushes/1h,
500 pushes/24h (standard-band base) or 10 ref deletes/24h. One row per
account per rule per window while over; windyadmin (the sync) exempt.
Nothing sits in the push path and nothing is refused. HOLD until
Telemetry Boss declares the shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 14:06:27 -04:00
Kit OC5
4c76b1b12a canary: end the hub session the login probe opens (journey cleanup rule)
All checks were successful
check / gate (push) Successful in 32s
canary / probe (push) Successful in 12s
identity.login created a live hub session every 10 min and never ended it.
It now logs out with the token it got: retried on 5xx / no response
(8 x 15 s), 401/404/410 = already over, any other 4xx fails fast, and a
cleanup it can't finish is reported as identity.logout DOWN "CLEANUP
FAILED" (alerts + red run). The hub's /auth/logout revokes every refresh
token of the account (verified live), so the next run's logout heals a
leftover; no ledger needed. Proven end to end: login 200, logout 200,
10/10 checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 13:39:55 -04:00
Kit OC5
2d4fadb090 sync: bound the janitor and telemetry steps (docker exec hangs in an IO stall)
Some checks failed
canary / probe (push) Has been cancelled
check / gate (push) Has been cancelled
09-23 16:43Z the Veron data2 SMR stall left runc exec in D state; the
janitor's docker exec never returned, so the sync sat 'activating' and no
repo mirrored or got a status for any lane. Both steps are non-fatal;
now they time out (120 s / 180 s) and the run continues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:54:34 -04:00
Kit OC5
e3b69fa759 telemetry: UPDATE 7 — read the ingest body; count quarantined + dropped on heartbeats
Some checks failed
canary / probe (push) Has been cancelled
check / gate (push) Has been cancelled
The ledger answers 202 even when it quarantines rows. Both emitters now log
a warning with the reasons and report service.health.telemetry_quarantined
and telemetry_dropped (API: buffer overflow; sync: 0 by construction, since
a failed send keeps cursor + spool). HOLD until Telemetry Boss declares both
keys on windy-git's two service.health shapes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:32:28 -04:00
Kit OC5
4acf50d9ef bridge tests: fake serves workflow contents; cover invalid-workflow status
All checks were successful
check / gate (push) Successful in 23s
b7a7e94 made the bridge read workflow files, which the strict fake Gitea
refused (7 red). The fake now serves contents (404 when absent), and new
tests cover: error posted with no runs, valid files add nothing, no repost,
.gitea/workflows wins over .github/workflows, and each workflow_problem
shape. pyyaml declared in dev extras (the bridge imports it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:31:19 -04:00
Kit OC5
b7a7e94df0 bridge: post an error status when Windy Git ignores an invalid workflow
Gitea drops an invalid workflow file with one log line and fires no run, so
the GitHub PR showed nothing and lanes waited for CI that never came
(windytalk #100). The bridge now reads each workflow file at the commit it
reports on and posts windy-git/<wf>/workflow = error with the reason.
Verified: 0 false positives on all 23 bridged repos' main; catches
windytalk #100's broken commits (invalid YAML at line 12), fix commit clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:29:12 -04:00