CI: redeploy ok-dspace on pushes to clarin-v7 - #1393
Conversation
…branch
Sends a repository_dispatch to ufal/dspace-k8s once the images this environment
consumes have actually been pushed. That repository pins the tag to git and an
in-cluster reconciler applies it, so this job records a version and nothing
more - no deployment step and no cluster credential exists here, or anywhere in
GitHub.
Runs only for pushes to the default branch of the canonical repository, so a
pull request builds images but never triggers a deploy.
The token is a fine-grained PAT scoped to ufal/dspace-k8s with Contents: write,
which is what POST /repos/{owner}/{repo}/dispatches requires. A workflow's own
GITHUB_TOKEN cannot act on another repository, so this credential is
unavoidable; it is held as an organisation secret shared with this repository.
There was a problem hiding this comment.
Pull request overview
This PR extends the existing Docker image workflow by adding a post-build job which, on pushes to clarin-v7 in ufal/clarin-dspace, sends a repository_dispatch event to ufal/dspace-k8s so that the ok-dspace environment can pin the newly built image tag/sha.
Changes:
- Add a
deploy-ok-dspacejob to.github/workflows/docker.ymlgated to pushes onclarin-v7in the upstream repo. - Ensure the dispatch runs only after both
dspaceanddspace-solrimages are built/pushed (needs: [dspace, dspace-solr]).
The section header said "Redeploy" and the step was called "Trigger deployment", but this job only sends a repository_dispatch - the deploying happens in ufal/dspace-k8s and, ultimately, in the cluster. Renamed both so the workflow logs say what ran. Also names `clarin-v7` explicitly instead of "the default branch", since that is the literal value the guard matches and the two could drift apart.
The job authenticates with a fine-grained PAT and never uses GITHUB_TOKEN, but
inherited the workflow-level permissions anyway - including `packages: write` in
dspace-angular, which it has no use for. `permissions: {}` limits what a
compromised third-party action could reach from this job.
| permissions: {} | ||
| steps: | ||
| - name: Notify ufal/dspace-k8s | ||
| uses: peter-evans/repository-dispatch@v4 |
There was a problem hiding this comment.
don't use and action, hand roll it with curl (or gh cli if possible)
There was a problem hiding this comment.
Done — gh it is, since ubuntu-latest ships both gh (2.96.0) and jq (1.7.1), so no download is needed either.
- name: Notify ufal/dspace-k8s
env:
GH_TOKEN: ${{ secrets.OK_DSPACE_DEPLOY_TOKEN }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
jq -n --arg sha "${SHA}" \
'{event_type: "deploy-ok-dspace",
client_payload: {component: "backend", sha: $sha}}' \
| gh api -X POST repos/ufal/dspace-k8s/dispatches --input -The payload is built by jq from an --arg rather than interpolated into a JSON string literal, so the value is a JSON string by construction instead of by careful quoting. Verified the emitted payload carries the same fields and values the action was sending, so nothing changes on the receiving end in pin-ok-dspace.yml. (Same JSON, not the same bytes — jq pretty-prints where the action sent compact; the API parses either.) gh api exits non-zero on an HTTP error, so a rejected dispatch still fails the job.
The real gain is that the PAT is no longer in the environment of third-party code for the sake of one POST. I also fixed the permissions: {} comment, which justified itself by "limits what a compromised third-party action could reach" — there is no longer one. Least privilege still applies, just for the plain reason that this job authenticates with the PAT and never touches GITHUB_TOKEN.
actionlint with shellcheck is clean.
peter-evans/repository-dispatch@v4 ran with the deploy PAT in its
environment to make a single POST. ubuntu-latest already ships gh and
jq, so the same call is three lines with no third-party code in the
credential's blast radius.
jq builds the payload from an --arg rather than interpolating the sha
into a JSON string, so the value is a JSON string by construction. The
request body is identical to what the action sent.
The permissions comment no longer justifies itself by third-party
actions, since there are none here now; permissions: {} still stands on
its own, because the job authenticates with the PAT and never touches
GITHUB_TOKEN.
Appends a
deploy-ok-dspacejob todocker.ymlthat notifiesufal/dspace-k8sonce the images this test environmentconsumes have been pushed. Target environment: https://ok-dspace.dyn.cloud.e-infra.cz.
This job records a version; it does not deploy. It sends a
repository_dispatch;dspace-k8spins the tag to git and a reconciler inside the cluster applies it. No deployment step and no cluster
credential exists in this repository — or anywhere in GitHub.
needs: [dspace, dspace-solr]— both images build from this same commit, so ok-dspace pins oneSHA for the pair; waiting for both avoids dispatching a half-built version.
clarin-v7inufal/clarin-dspace, so a pull request builds imagesbut never triggers a deploy, and forks never fire it.
secrets.OK_DSPACE_DEPLOY_TOKENis a fine-grained PAT scoped toufal/dspace-k8swithContents: write, which is what
POST /repos/{owner}/{repo}/dispatchesrequires. It is alreadyconfigured as an organisation secret. A workflow's own
GITHUB_TOKENcannot act on anotherrepository, so this credential is unavoidable.
Nothing else in the build changes.
Depends on ufal/dspace-k8s#39, which defines the
deploy-ok-dspacedispatch type. This PR isinert until that merges — the dispatch simply has no listener.