Skip to content

Commit 622c5d9

Browse files
committed
Initial commit: setup-takumi-guard-npm action
Composite GitHub Action that configures npm to use the Takumi Guard registry via OIDC token exchange.
0 parents  commit 622c5d9

File tree

5 files changed

+229
-0
lines changed

5 files changed

+229
-0
lines changed

.github/workflows/test.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Test
2+
on:
3+
push:
4+
branches: [main]
5+
pull_request:
6+
branches: [main]
7+
8+
jobs:
9+
lint:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Validate action.yml
15+
run: |
16+
python3 -c "import yaml; yaml.safe_load(open('action.yml'))"
17+
echo "action.yml is valid YAML"
18+
19+
- name: Check required fields
20+
run: |
21+
grep -q 'using:.*composite' action.yml
22+
grep -q "bot-id:" action.yml
23+
echo "Required fields present"

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules/
2+
.npmrc
3+
*.log
4+
.DS_Store
5+
*.pem
6+
*.pub

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Shisho Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<h1 align="center">setup-takumi-guard-npm</h1>
2+
3+
<p align="center">
4+
GitHub Action to configure npm with <a href="https://shisho.dev">Takumi Guard</a> registry auth via OIDC.
5+
</p>
6+
7+
<p align="center">
8+
<a href="https://github.com/flatt-security/setup-takumi-guard-npm/actions"><img src="https://github.com/flatt-security/setup-takumi-guard-npm/actions/workflows/test.yml/badge.svg" alt="CI" /></a>
9+
</p>
10+
11+
## Usage
12+
13+
```yaml
14+
jobs:
15+
build:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
id-token: write
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- uses: flatt-security/setup-takumi-guard-npm@v1
23+
with:
24+
bot-id: "BT01EXAMPLE..." # from Shisho Cloud console
25+
26+
- run: npm install
27+
- run: npm test
28+
```
29+
30+
The Bot ID is a public reference key, not a secret. You can find it on the Shisho Cloud console settings page. Storing it as a GitHub secret also works if you prefer.
31+
32+
## What this does
33+
34+
1. Requests an OIDC token from GitHub's token endpoint
35+
2. Exchanges it for a short-lived access token via `POST {sts-url}/bots/exchange`
36+
3. Writes registry URL and auth token to a project-level `.npmrc`
37+
38+
After that, `npm install` goes through Takumi Guard. No PATs or long-lived tokens involved.
39+
40+
## Inputs
41+
42+
| Input | Required | Default | Description |
43+
|-------|----------|---------|-------------|
44+
| `bot-id` | Yes | — | Bot ID from Shisho Cloud |
45+
| `sts-url` | No | `https://sts.shisho.dev` | STS endpoint |
46+
| `registry-url` | No | `https://npm.takumi-guard.shisho.dev` | Registry endpoint |
47+
| `expires-in` | No | `1800` | Token lifetime in seconds (max 86400) |
48+
49+
## Outputs
50+
51+
| Output | Description |
52+
|--------|-------------|
53+
| `token-expires-at` | ISO 8601 expiration timestamp |
54+
55+
## Security
56+
57+
Tokens are short-lived (30 min by default, 24h max) and masked in workflow logs. The action writes to project-level `.npmrc` only, so your global npm config is untouched. Existing scoped registries (e.g. `@myorg:registry=...`) are preserved.
58+
59+
## Troubleshooting
60+
61+
| Error | Cause | Fix |
62+
|-------|-------|-----|
63+
| `OIDC not available` | Missing permission | Add `id-token: write` to your job's `permissions` |
64+
| `invalid ID token` | Trust condition mismatch | Check the bot's trust settings in Shisho Cloud |
65+
| `invalid request` | Bad bot-id format | Double-check the bot-id value |
66+
67+
## License
68+
69+
[MIT](LICENSE)

action.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: 'Setup Takumi Guard npm Registry'
2+
description: 'Configure npm to use Takumi Guard registry with OIDC-based auth'
3+
author: 'Shisho Security'
4+
5+
branding:
6+
icon: 'shield'
7+
color: 'blue'
8+
9+
inputs:
10+
bot-id:
11+
description: 'Bot ID from Shisho Cloud console'
12+
required: true
13+
sts-url:
14+
description: 'STS service URL'
15+
required: false
16+
default: 'https://sts.cloud.shisho.dev'
17+
registry-url:
18+
description: 'npm registry URL'
19+
required: false
20+
default: 'https://npm.takumi-guard.shisho.dev'
21+
expires-in:
22+
description: 'Token expiration in seconds (max 86400)'
23+
required: false
24+
default: '1800'
25+
26+
outputs:
27+
token-expires-at:
28+
description: 'ISO 8601 timestamp when the token expires'
29+
value: ${{ steps.set-outputs.outputs.token-expires-at }}
30+
31+
runs:
32+
using: 'composite'
33+
steps:
34+
- name: Get OIDC token
35+
id: oidc
36+
shell: bash
37+
run: |
38+
if [ -z "$ACTIONS_ID_TOKEN_REQUEST_URL" ]; then
39+
echo "::error::OIDC not available. Add 'permissions: { id-token: write }' to your job."
40+
exit 1
41+
fi
42+
43+
OIDC_TOKEN=$(curl -sS -f \
44+
-H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
45+
"${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=takumi-guard.shisho.dev" \
46+
| jq -r '.value')
47+
48+
if [ -z "$OIDC_TOKEN" ] || [ "$OIDC_TOKEN" = "null" ]; then
49+
echo "::error::Failed to get OIDC token. Ensure id-token: write permission is set."
50+
exit 1
51+
fi
52+
53+
echo "::add-mask::${OIDC_TOKEN}"
54+
echo "oidc_token=${OIDC_TOKEN}" >> "$GITHUB_OUTPUT"
55+
56+
- name: Exchange for STS access token
57+
id: exchange
58+
shell: bash
59+
env:
60+
OIDC_TOKEN: ${{ steps.oidc.outputs.oidc_token }}
61+
BOT_ID: ${{ inputs.bot-id }}
62+
STS_URL: ${{ inputs.sts-url }}
63+
EXPIRES_IN: ${{ inputs.expires-in }}
64+
run: |
65+
RESPONSE=$(curl -sS -f -X POST "${STS_URL}/bots/exchange" \
66+
-H "Content-Type: application/json" \
67+
-d "{\"bot_id\": \"${BOT_ID}\", \"id_token\": \"${OIDC_TOKEN}\", \"expires_in\": ${EXPIRES_IN}}")
68+
69+
if [ $? -ne 0 ]; then
70+
echo "::error::STS token exchange request failed. Check sts-url and network connectivity."
71+
exit 1
72+
fi
73+
74+
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')
75+
EXPIRES_IN_ACTUAL=$(echo "$RESPONSE" | jq -r '.expires_in')
76+
77+
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" = "null" ]; then
78+
ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message // "Unknown error"')
79+
echo "::error::Token exchange failed: ${ERROR_MSG}"
80+
exit 1
81+
fi
82+
83+
echo "::add-mask::${ACCESS_TOKEN}"
84+
echo "access_token=${ACCESS_TOKEN}" >> "$GITHUB_OUTPUT"
85+
86+
# Calculate expiration timestamp (Linux date -d, macOS date -v fallback)
87+
EXPIRES_AT=$(date -u -d "+${EXPIRES_IN_ACTUAL} seconds" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || \
88+
date -u -v+"${EXPIRES_IN_ACTUAL}"S +%Y-%m-%dT%H:%M:%SZ)
89+
echo "expires_at=${EXPIRES_AT}" >> "$GITHUB_OUTPUT"
90+
91+
- name: Configure npm
92+
shell: bash
93+
env:
94+
ACCESS_TOKEN: ${{ steps.exchange.outputs.access_token }}
95+
REGISTRY_URL: ${{ inputs.registry-url }}
96+
run: |
97+
REGISTRY_HOST=$(echo "$REGISTRY_URL" | sed 's|^https://||' | sed 's|/$||')
98+
99+
npm config set registry "${REGISTRY_URL}/" --location=project
100+
npm config set "//${REGISTRY_HOST}/:_authToken" "${ACCESS_TOKEN}" --location=project
101+
102+
echo "::notice::Configured npm to use Takumi Guard registry at ${REGISTRY_URL}"
103+
104+
- name: Set outputs
105+
id: set-outputs
106+
shell: bash
107+
env:
108+
EXPIRES_AT: ${{ steps.exchange.outputs.expires_at }}
109+
run: |
110+
echo "token-expires-at=${EXPIRES_AT}" >> "$GITHUB_OUTPUT"

0 commit comments

Comments
 (0)