Repository navigation
Expand file tree
/
Copy pathaction.yml
More file actions
184 lines (177 loc) · 7.77 KB
/
Copy pathaction.yml
File metadata and controls
184 lines (177 loc) · 7.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# The GitHub Action: a commit that changes a settings folder becomes a new settings image.
# Design: docs/github-action.md. It runs the CLI (docs/cli.md), built from this ref's own source.
#
# Every input reaches a script through env:, never through ${{ }} inside run:, so a branch name
# or path is data, not shell.
name: Push settings image
description: Turn a folder of settings into a mountable OCI image and push it
author: ConfigButler
branding:
icon: package
color: blue
inputs:
path:
description: The settings folder, relative to the workspace.
required: true
repository:
description: Where to push, without a tag, e.g. ghcr.io/acme/app-settings.
required: true
branch-tag:
description: The branch to derive a moving tag from. Set it to '' for none.
default: ${{ github.ref_name }}
timestamp-tag:
description: >-
The branch for a tag that never moves and sorts by commit time,
<branch>-<unix commit time>-<sha7>; usually the workflow's github.ref_name. What Flux image
automation follows (docs/flux.md). Empty for none.
default: ''
tags:
description: Extra tags, one per line.
default: ''
sensitive-kinds:
description: >-
Kinds that must be SOPS-encrypted like a Secret, one per line, as group/Kind (Kind alone for
the core group).
default: ''
provenance:
description: "'false' builds no provenance referrer and no sha- tag."
default: 'true'
provenance-author:
description: >-
How much of the commit author goes into the provenance referrer, which is public wherever
the image is: none, name or full (name and email).
default: none
username:
description: Registry username.
default: ${{ github.actor }}
password:
description: >-
Registry password. When no password, registry-token or oidc-audience is set, a push to
ghcr.io uses the workflow's github.token, and any other registry uses the Docker config, as
docker/login-action leaves it.
default: ''
registry-token:
description: >-
A registry token, sent unchanged as "Authorization: Bearer" to the registry and to no other
host. At most one of password, registry-token and oidc-audience.
default: ''
oidc-audience:
description: >-
Request the workflow's GitHub OIDC token for this audience (use the registry host) and send
it as the registry token. Needs `permissions: id-token: write`.
default: ''
plain-http:
description: "'true' talks HTTP to the registry (a service-container registry)."
default: 'false'
outputs:
digest:
description: The image digest.
value: ${{ steps.push.outputs.digest }}
reference:
description: repository@digest, for volumes[].image.reference.
value: ${{ steps.push.outputs.reference }}
tags:
description: The tags set, comma-separated.
value: ${{ steps.push.outputs.tags }}
changed:
description: "'false' when the image and every tag were already there."
value: ${{ steps.push.outputs.changed }}
commit:
description: The commit that last changed the folder, as in the provenance; empty without it.
value: ${{ steps.push.outputs.commit }}
skipped:
description: Known top-level files left out of the image (README.md, ...), comma-separated.
value: ${{ steps.push.outputs.skipped }}
runs:
using: composite
steps:
# With `uses: ./`, github.action_path ends in "/./", which setup-go refuses as a cache path.
- name: Resolve the action's path
id: source
shell: bash
run: echo "dir=$(cd "$GITHUB_ACTION_PATH" && pwd -P)" >> "$GITHUB_OUTPUT"
- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: ${{ steps.source.outputs.dir }}/go.mod
cache-dependency-path: ${{ steps.source.outputs.dir }}/go.sum
- name: Build settings-image
shell: bash
working-directory: ${{ github.action_path }}
run: CGO_ENABLED=0 go build -trimpath -o "$RUNNER_TEMP/settings-image" ./cmd/settings-image
- name: Push the settings image
id: push
shell: bash
env:
SI_PATH: ${{ inputs.path }}
SI_REPOSITORY: ${{ inputs.repository }}
SI_BRANCH_TAG: ${{ inputs.branch-tag }}
SI_TIMESTAMP_TAG: ${{ inputs.timestamp-tag }}
SI_TAGS: ${{ inputs.tags }}
SI_SENSITIVE_KINDS: ${{ inputs.sensitive-kinds }}
SI_PROVENANCE: ${{ inputs.provenance }}
SI_PROVENANCE_AUTHOR: ${{ inputs.provenance-author }}
SI_USERNAME: ${{ inputs.username }}
SI_PASSWORD: ${{ inputs.password }}
SI_REGISTRY_TOKEN: ${{ inputs.registry-token }}
SI_OIDC_AUDIENCE: ${{ inputs.oidc-audience }}
SI_GITHUB_TOKEN: ${{ github.token }}
SI_PLAIN_HTTP: ${{ inputs.plain-http }}
run: |
set -euo pipefail
args=(push "$SI_PATH" --repository "$SI_REPOSITORY" --json)
if [[ -n "$SI_BRANCH_TAG" ]]; then args+=(--branch-tag "$SI_BRANCH_TAG"); fi
if [[ -n "$SI_TIMESTAMP_TAG" ]]; then args+=(--timestamp-tag "$SI_TIMESTAMP_TAG"); fi
while IFS= read -r tag; do
tag="${tag//[[:space:]]/}"
if [[ -n "$tag" ]]; then args+=(--tag "$tag"); fi
done <<< "$SI_TAGS"
while IFS= read -r kind; do
kind="${kind//[[:space:]]/}"
if [[ -n "$kind" ]]; then args+=(--sensitive-kind "$kind"); fi
done <<< "$SI_SENSITIVE_KINDS"
if [[ "$SI_PROVENANCE" == "false" ]]; then
args+=(--no-provenance)
elif [[ -n "$SI_PROVENANCE_AUTHOR" ]]; then
args+=(--provenance-author "$SI_PROVENANCE_AUTHOR")
fi
if [[ "$SI_PLAIN_HTTP" == "true" ]]; then args+=(--plain-http); fi
# One credential (docs/cli.md §4). github.token is a secret of GitHub: it goes to ghcr.io
# only, and only when no other credential is set; otherwise the Docker config applies.
n=0
for v in "$SI_PASSWORD" "$SI_REGISTRY_TOKEN" "$SI_OIDC_AUDIENCE"; do [[ -z "$v" ]] || n=$((n + 1)); done
if (( n > 1 )); then
echo "::error::Set at most one of password, registry-token and oidc-audience."
exit 2
fi
if [[ -n "$SI_PASSWORD" ]]; then
export SETTINGS_IMAGE_USERNAME="$SI_USERNAME" SETTINGS_IMAGE_PASSWORD="$SI_PASSWORD"
elif [[ -n "$SI_REGISTRY_TOKEN" ]]; then
export SETTINGS_IMAGE_REGISTRY_TOKEN="$SI_REGISTRY_TOKEN"
elif [[ -n "$SI_OIDC_AUDIENCE" ]]; then
# Requested here, right before the push: the token lives minutes.
if [[ -z "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" ]]; then
echo "::error::oidc-audience needs 'permissions: id-token: write' on the job."
exit 2
fi
audience="$(jq -rn --arg a "$SI_OIDC_AUDIENCE" '$a | @uri')"
token="$(curl -fsS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=$audience" | jq -r .value)"
echo "::add-mask::$token"
export SETTINGS_IMAGE_REGISTRY_TOKEN="$token"
elif [[ "$SI_REPOSITORY" == ghcr.io/* ]]; then
export SETTINGS_IMAGE_USERNAME="$SI_USERNAME" SETTINGS_IMAGE_PASSWORD="$SI_GITHUB_TOKEN"
fi
out="$("$RUNNER_TEMP/settings-image" "${args[@]}")"
echo "$out" | jq .
{
echo "digest=$(jq -r .digest <<< "$out")"
echo "reference=$(jq -r .reference <<< "$out")"
echo "tags=$(jq -r '.tags | join(",")' <<< "$out")"
echo "changed=$(jq -r .changed <<< "$out")"
echo "commit=$(jq -r '.commit // ""' <<< "$out")"
echo "skipped=$(jq -r '.skipped | join(",")' <<< "$out")"
} >> "$GITHUB_OUTPUT"
if [[ "$(jq -r .changed <<< "$out")" == "false" ]]; then
echo "::notice::Nothing to do: $(jq -r .reference <<< "$out") and its tags were already there."
fi