|
| 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