security: a real CI check before auto-merge; .github/ always protected (#46)

- checks(): the worker's own time/worker-run status can block or delay a merge but never counts as green
- dispatch_ci(): with no other check on the head, Time runs TIME_CI_WORKFLOW (ci.yml, workflow_dispatch) on the PR branch and waits; beat ci-dispatched, once
- ci.yml accepts workflow_dispatch
- touches_protected(): .github/ is always protected, whatever TIME_PROTECTED says
- labs-aicharts.yml: deploy URL via env, not ${{ }} in the script
- tests: worker-status-only no longer merges; dispatch once; real context merges


Claude-Session: https://claude.ai/code/session_01CYHXFvWMCs1GUmRmpySqQ6

Co-authored-by: claude <noreply@anthropic.com>
This commit was merged in pull request #46.
This commit is contained in:
teahubxyzandclaude authored and GitHub committed 2026-10-13 21:33:35 -07:00
1 parent 17e51a6b08
commit 8c6ad054b9
5 files changed
+53 -14

No files matched your search

+3
View File
@@ -3,6 +3,9 @@
## [Unreleased]
### Security
- The worker's own commit status (`time/worker-run`) can fail or delay a merge but never earns one: with no other check on the PR head, Time dispatches the project's CI workflow on the PR branch (`TIME_CI_WORKFLOW`, default `ci.yml`, which must accept `workflow_dispatch`; GitHub skips `pull_request` runs for pushes made with the Actions token) and merges on that. `off` keeps the old "no checks" stop.
- `.github/` is protected from auto-merge whatever `TIME_PROTECTED` says.
- `labs-aicharts.yml` passes the deploy URL through `env` instead of interpolating it into the shell.
- Time's state comments (`<!-- time {...} -->` beats) count only when written by `github-actions[bot]`; a pasted marker from anyone else is ignored. A stranger on a public repo could otherwise steer a card to merge a chosen PR or build a chosen page.
- `/time retry` and "Approve"/"Object" comments count only from the owner, members, collaborators and Time itself; any other bot is a stranger too.
- The protected-path check reads every file of a PR (not the first 100) and counts a rename under both names.