Skip to content

Repositories, routing and triggers: runs start from a git push - #7

Merged
KristiforMilchev merged 3 commits into
mainfrom
triggers
Nov 3, 2026
Merged

KristiforMilchev merged 3 commits into
mainfrom
triggers

Conversation

@KristiforMilchev

Copy link
Copy Markdown
Contributor

Runs now start from a git push, whether the repository is on your own git server or on GitHub. No forge integrations: both paths use the same trigger API and CLI code, all ours.

This branch is built on #6 (secrets), so it contains that commit too. Merge #6 first; this PR's diff then shrinks to its own changes.

Repository registry (controller repo create|list|delete|token create)

  • Each repository has a clone URL and routing rules that decide the pool. The first matching rule wins, and an event that matches no rule starts no run. Example: -route push:main=trusted -route tag:v*=release -route pull_request=untrusted. The default sends everything to untrusted.
  • Trigger tokens are scoped to one repository and stored only as hashes.
  • An optional read credential for private repositories is encrypted, and is given to workers with each job, never stored in the job.

Trigger API (TriggerService: Trigger, GetRun, GetJobLog)

  • A token reaches only its own repository's runs and logs.
  • The controller reads .opifica/pipeline.yaml at the commit, from its own mirror. The caller can neither supply the pipeline nor choose the pool.

Your own git server: opifica hook post-receive is the hook for bare repositories. It never fails a push, since the push has already been accepted, and it prints the runs it started:

remote: opifica: main: run 0b6f… started in pool trusted (3 jobs)

GitHub: opifica trigger -wait, in a workflow step (examples/github-actions.yml).

  • It reads the workflow's event. For pull requests it builds the head commit, not GitHub's temporary merge commit.
  • It prints the run's output, exits with the run's result so the check passes or fails in GitHub, and adds a summary table to the workflow run.

Tests

  • Real bare repository, real git hook: a git push of a branch and a tag starts two runs, in trusted and release. A push no rule matches is reported to the pusher, and the push still succeeds.
  • The real opifica binary with GitHub Actions' environment: a succeeding run exits 0 with the output and summary. A failing run exits 1 and shows the failing job's exit code.
  • Authorization: an unknown token, another repository's token (for triggering, reading runs and reading logs), and a revoked token are all rejected.
  • Credentials: a read credential reaches the worker, and is stored neither in the job nor unencrypted.
  • Unit tests for routing, including that a pull request is routed by its target branch, never its source branch, so naming your branch main gets nothing. Also the GitHub event parsing.
  • The integration suite passes 5 times in a row under the race detector.

Next: opifica-git, so that creating a repository makes the bare repo and installs this hook for you. It still needs a decision: push over HTTPS, SSH, or both.

🤖 Generated with Claude Code

KristiforMilchev and others added 3 commits November 3, 2026 16:06
- Secrets encrypted with AES-256-GCM under a key file only the controller
  reads; each ciphertext is bound to its secret's name
- A request is granted only if the worker holds the job, the job token is
  the current attempt's, the job lists the secret, and the admin's policy
  allows the run: repositories, pools, refs, and pull requests (off by
  default)
- Every request is recorded, granted or not; without an audit record the
  secret isn't handed out
- controller secret set (value from stdin), list, delete, access
- Tests: granted and masked end to end, each policy denial, and attempts
  around the checks (unlisted secret, wrong token, another worker's job);
  each check verified by removing it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Repository registry: clone URL, routing rules (event + ref -> pool,
  first match wins, default everything -> untrusted), trigger tokens
  (hash-only), optional read credential encrypted with the secrets key
- TriggerService: Trigger, GetRun, GetJobLog. A token only reaches its own
  repository. The controller reads the pipeline at the commit itself from
  its own mirror; the caller can't supply it or choose the pool
- opifica hook post-receive: the git hook for bare repositories on your
  own server; never fails the push, prints the runs for the pusher
- opifica trigger -wait: for GitHub Actions (reads the workflow's event;
  for pull requests the head commit, not GitHub's merge commit), follows
  the logs, exits with the run's result, writes a step summary
- Repository credentials reach workers with each job, never stored in it
- Git mirror moved to internal/gitmirror, shared by worker and controller
- controller repo create|list|delete|token create; serve -allow-local-repos
- Docs: no forge providers; your own git server or GitHub; example workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tains #6)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KristiforMilchev
KristiforMilchev merged commit 26e9889 into main Nov 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant