Skip to content

Commit ed7bd2f

Browse files
committed
action: generate action.yml from CUE
Embed the JS from a separate JavaScript file making editing that in future easier. There are no changes to the code itself, but for the formatting changes applied by prettier. We will setup npm etc in a later CL, making minimal changes here for now. Also test the action as part of this repo's CI. A simple attempt to use the action is sufficient, because this triggers the fetching of a token from the Central Registry. Signed-off-by: Paul Jolly <paul@myitcv.io> Change-Id: I4066b03b798c2401d8fe096f85b3c64d0caefc6e Reviewed-on: https://review.gerrithub.io/c/cue-labs/registry-login-action/+/1230255 Reviewed-by: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: CUE porcuepine <cue.porcuepine@gmail.com>
1 parent 7517c28 commit ed7bd2f

6 files changed

Lines changed: 167 additions & 50 deletions

File tree

.github/workflows/trybot.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ jobs:
1818
run:
1919
shell: bash --noprofile --norc -euo pipefail {0}
2020
runs-on: namespace-profile-linux-amd64
21+
permissions:
22+
id-token: write
2123
steps:
2224
- name: Checkout code
2325
uses: actions/checkout@v5
@@ -53,3 +55,5 @@ jobs:
5355
run: |-
5456
echo "github.event.head_commit.message contains Dispatch-Trailer but we are on a protected branch"
5557
false
58+
- name: Login to CUE Central Registry
59+
uses: ./

action.cue

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@extern(embed)
2+
3+
package action
4+
5+
name: "Login to CUE Registry via GitHub OIDC"
6+
description: "Authenticate to a CUE registry using GitHub OIDC tokens"
7+
branding: {
8+
icon: "log-in"
9+
color: "blue"
10+
}
11+
inputs: {
12+
registry: {
13+
description: "CUE registry"
14+
required: false
15+
default: "registry.cue.works"
16+
}
17+
update_logins: {
18+
description: "Whether to update the local CUE logins.json file"
19+
required: false
20+
default: "true"
21+
}
22+
}
23+
outputs: access_token: {
24+
description: "The access token obtained from the registry"
25+
value: "${{ steps.oidc.outputs.access_token }}"
26+
}
27+
runs: {
28+
using: "composite"
29+
steps: [{
30+
name: "Get OIDC token and login"
31+
id: "oidc"
32+
uses: "actions/github-script@v7"
33+
with: {
34+
script: _ @embed(file=action.js,type=text)
35+
}
36+
}]
37+
}

action.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const registry = "${{ inputs.registry }}";
2+
const registryUrl = `https://${registry}`;
3+
4+
// Get OIDC token with registry as audience
5+
let token = null;
6+
try {
7+
token = await core.getIDToken(registryUrl);
8+
} catch (e) {
9+
throw new Error(
10+
`Failed to obtain OIDC token. Did you specify the id-token: write permission? ${e.message}`,
11+
);
12+
}
13+
14+
// Exchange OIDC token for registry access token
15+
const res = await fetch(`${registryUrl}/login/oidc/github`, {
16+
method: "POST",
17+
headers: {
18+
"Content-Type": "application/json",
19+
},
20+
body: JSON.stringify({ id_token: token }),
21+
});
22+
if (!res.ok) {
23+
let msg = `HTTP ${res.status} ${res.statusText}`;
24+
try {
25+
const data = await res.json();
26+
msg = data.error_description || JSON.stringify(data);
27+
} catch (e) {}
28+
throw new Error(`${registry}: ${msg}`);
29+
}
30+
const data = await res.json();
31+
core.setOutput("access_token", data.access_token);
32+
33+
// Write credentials to cue logins file if update_logins is true
34+
if ("${{ inputs.update_logins }}" === "true") {
35+
const fs = require("fs");
36+
const path = require("path");
37+
const homeDir = process.env.HOME || process.env.USERPROFILE;
38+
const configDir = path.join(homeDir, ".config", "cue");
39+
const loginsPath = path.join(configDir, "logins.json");
40+
41+
fs.mkdirSync(configDir, { recursive: true });
42+
43+
let logins = {};
44+
if (fs.existsSync(loginsPath)) {
45+
try {
46+
const content = fs.readFileSync(loginsPath, "utf8");
47+
if (content.trim()) {
48+
logins = JSON.parse(content);
49+
}
50+
} catch (err) {
51+
console.warn(
52+
"Failed to parse existing logins.json, will overwrite:",
53+
err.message,
54+
);
55+
}
56+
}
57+
58+
logins.registries = logins.registries || {};
59+
60+
logins.registries[registry] = {
61+
access_token: data.access_token,
62+
token_type: "Bearer",
63+
};
64+
65+
fs.writeFileSync(loginsPath, JSON.stringify(logins, null, 2) + "\\n");
66+
}

action.yml

Lines changed: 51 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,92 @@
1-
name: 'Login to CUE Registry via GitHub OIDC'
2-
description: 'Authenticate to a CUE registry using GitHub OIDC tokens'
1+
name: Login to CUE Registry via GitHub OIDC
2+
description: Authenticate to a CUE registry using GitHub OIDC tokens
33
branding:
4-
icon: 'log-in'
5-
color: 'blue'
6-
4+
icon: log-in
5+
color: blue
76
inputs:
87
registry:
9-
description: 'CUE registry'
8+
description: CUE registry
109
required: false
11-
default: 'registry.cue.works'
10+
default: registry.cue.works
1211
update_logins:
13-
description: 'Whether to update the local CUE logins.json file'
12+
description: Whether to update the local CUE logins.json file
1413
required: false
15-
default: 'true'
16-
14+
default: "true"
1715
outputs:
1816
access_token:
19-
description: 'The access token obtained from the registry'
17+
description: The access token obtained from the registry
2018
value: ${{ steps.oidc.outputs.access_token }}
21-
2219
runs:
23-
using: 'composite'
20+
using: composite
2421
steps:
2522
- name: Get OIDC token and login
2623
id: oidc
2724
uses: actions/github-script@v7
2825
with:
2926
script: |
30-
const registry = '${{ inputs.registry }}'
31-
const registryUrl = `https://${registry}`
32-
27+
const registry = "${{ inputs.registry }}";
28+
const registryUrl = `https://${registry}`;
29+
3330
// Get OIDC token with registry as audience
34-
let token = null
31+
let token = null;
3532
try {
36-
token = await core.getIDToken(registryUrl)
33+
token = await core.getIDToken(registryUrl);
3734
} catch (e) {
38-
throw new Error(`Failed to obtain OIDC token. Did you specify the id-token: write permission? ${e.message}`)
35+
throw new Error(
36+
`Failed to obtain OIDC token. Did you specify the id-token: write permission? ${e.message}`,
37+
);
3938
}
4039
4140
// Exchange OIDC token for registry access token
4241
const res = await fetch(`${registryUrl}/login/oidc/github`, {
43-
method: 'POST',
42+
method: "POST",
4443
headers: {
45-
'Content-Type': 'application/json'
44+
"Content-Type": "application/json",
4645
},
47-
body: JSON.stringify({ id_token: token })
48-
})
46+
body: JSON.stringify({ id_token: token }),
47+
});
4948
if (!res.ok) {
5049
let msg = `HTTP ${res.status} ${res.statusText}`;
5150
try {
52-
const data = await res.json()
53-
msg = data.error_description || JSON.stringify(data)
54-
} catch (e) {
55-
}
56-
throw new Error(`${registry}: ${msg}`)
51+
const data = await res.json();
52+
msg = data.error_description || JSON.stringify(data);
53+
} catch (e) {}
54+
throw new Error(`${registry}: ${msg}`);
5755
}
58-
const data = await res.json()
59-
core.setOutput('access_token', data.access_token)
56+
const data = await res.json();
57+
core.setOutput("access_token", data.access_token);
6058
6159
// Write credentials to cue logins file if update_logins is true
62-
if ('${{ inputs.update_logins }}' === 'true') {
63-
const fs = require('fs')
64-
const path = require('path')
65-
const homeDir = process.env.HOME || process.env.USERPROFILE
66-
const configDir = path.join(homeDir, '.config', 'cue')
67-
const loginsPath = path.join(configDir, 'logins.json')
68-
69-
fs.mkdirSync(configDir, { recursive: true })
70-
71-
let logins = {}
60+
if ("${{ inputs.update_logins }}" === "true") {
61+
const fs = require("fs");
62+
const path = require("path");
63+
const homeDir = process.env.HOME || process.env.USERPROFILE;
64+
const configDir = path.join(homeDir, ".config", "cue");
65+
const loginsPath = path.join(configDir, "logins.json");
66+
67+
fs.mkdirSync(configDir, { recursive: true });
68+
69+
let logins = {};
7270
if (fs.existsSync(loginsPath)) {
7371
try {
74-
const content = fs.readFileSync(loginsPath, 'utf8')
72+
const content = fs.readFileSync(loginsPath, "utf8");
7573
if (content.trim()) {
76-
logins = JSON.parse(content)
74+
logins = JSON.parse(content);
7775
}
7876
} catch (err) {
79-
console.warn('Failed to parse existing logins.json, will overwrite:', err.message)
77+
console.warn(
78+
"Failed to parse existing logins.json, will overwrite:",
79+
err.message,
80+
);
8081
}
8182
}
82-
83-
logins.registries = logins.registries || {}
84-
83+
84+
logins.registries = logins.registries || {};
85+
8586
logins.registries[registry] = {
8687
access_token: data.access_token,
87-
token_type: "Bearer"
88-
}
89-
90-
fs.writeFileSync(loginsPath, JSON.stringify(logins, null, 2) + '\n')
88+
token_type: "Bearer",
89+
};
90+
91+
fs.writeFileSync(loginsPath, JSON.stringify(logins, null, 2) + "\\n");
9192
}

gen.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package action
2+
3+
//go:generate go tool cue export -f -o action.yml

internal/ci/github/trybot.cue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,15 @@ workflows: trybot: _repo.bashWorkflow & {
2929

3030
jobs: test: {
3131
"runs-on": _repo.linuxMachine
32+
permissions: "id-token": "write"
3233

3334
steps: [
3435
for v in _repo.checkoutCode {v},
36+
37+
{
38+
name: "Login to CUE Central Registry"
39+
uses: "./"
40+
},
3541
]
3642
}
3743
}

0 commit comments

Comments
 (0)