@gtrevorrow/oci-token-exchange 1.0.0-20250417-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,35 @@
1
+ Copyright (c) 2024 Oracle and/or its affiliates.
2
+
3
+ The Universal Permissive License (UPL), Version 1.0
4
+
5
+ Subject to the condition set forth below, permission is hereby granted to any
6
+ person obtaining a copy of this software, associated documentation and/or data
7
+ (collectively the "Software"), free of charge and under any and all copyright
8
+ rights in the Software, and any and all patent rights owned or freely
9
+ licensable by each licensor hereunder covering either (i) the unmodified
10
+ Software as contributed to or provided by such licensor, or (ii) the Larger
11
+ Works (as defined below), to deal in both
12
+
13
+ (a) the Software, and
14
+ (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
15
+ one is included with the Software (each a "Larger Work" to which the Software
16
+ is contributed by such licensors),
17
+
18
+ without restriction, including without limitation the rights to copy, create
19
+ derivative works of, display, perform, and distribute the Software and make,
20
+ use, sell, offer for sale, import, export, have made, and have sold the
21
+ Software and the Larger Work(s), and to sublicense the foregoing rights on
22
+ either these or other terms.
23
+
24
+ This license is subject to the following condition:
25
+ The above copyright notice and either this complete permission notice or at
26
+ a minimum a reference to the UPL must be included in all copies or
27
+ substantial portions of the Software.
28
+
29
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,329 @@
1
+ # OCI Token Exchange
2
+
3
+ ## Table of Contents
4
+
5
+ - [Installation](#installation)
6
+ - [As GitHub Action](#as-github-action)
7
+ - [As CLI Tool](#as-cli-tool)
8
+ - [Usage](#usage)
9
+ - [GitHub Actions](#github-actions)
10
+ - [GitLab CI](#gitlab-ci)
11
+ - [Option 1: Building from Source](#option-1-building-from-source)
12
+ - [Option 2: Using npm Package](#option-2-using-npm-package)
13
+ - [Bitbucket Pipelines](#bitbucket-pipelines)
14
+ - [Option 1: Building from Source](#option-1-building-from-source-1)
15
+ - [Option 2: Using npm Package](#option-2-using-npm-package-1)
16
+ - [Standalone CLI Usage](#standalone-cli-usage)
17
+ - [Debugging](#debugging)
18
+ - [Environment Variables / Github Secrets](#environment-variables--github-secrets)
19
+ - [Environment Variable Handling](#environment-variable-handling)
20
+ - [How it Works](#how-it-works)
21
+ - [Semantic Versioning](#semantic-versioning)
22
+ - [License](#license)
23
+ - [Contributing](#contributing)
24
+
25
+ # OCI Token Exchange
26
+
27
+ A tool to exchange OIDC tokens for [OCI session tokens](https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/clitoken.htm), supporting multiple CI platforms:
28
+ - GitHub Actions
29
+ - GitLab CI
30
+ - Bitbucket Pipelines
31
+
32
+ ## Installation
33
+
34
+ ### As GitHub Action
35
+ ```yaml
36
+ - uses: gtrevorrow/oci-token-exchange-action@v1
37
+ ```
38
+
39
+ ### As CLI Tool
40
+ ```bash
41
+ npm install -g @gtrevorrow/oci-token-exchange
42
+
43
+ # Install the latest version globally
44
+ npm install -g @gtrevorrow/oci-token-exchange
45
+
46
+ # Install a specific version globally (e.g., 1.2.3)
47
+ npm install -g @gtrevorrow/oci-token-exchange@1.2.3
48
+
49
+ # Install a version with a specific tag (e.g., beta)
50
+ npm install -g @gtrevorrow/oci-token-exchange@beta
51
+ ```
52
+
53
+ ## Usage
54
+
55
+ ### GitHub Actions
56
+ ```yaml
57
+ - uses: gtrevorrow/oci-token-exchange-action@v1
58
+ with:
59
+ oidc_client_identifier: ${{ secrets.OIDC_CLIENT_ID }}
60
+ domain_base_url: ${{ secrets.DOMAIN_URL }}
61
+ oci_tenancy: ${{ secrets.OCI_TENANCY }}
62
+ oci_region: ${{ secrets.OCI_REGION }}
63
+ ```
64
+
65
+ ### GitLab CI
66
+
67
+ #### Option 1: Building from Source
68
+
69
+ This example clones the repository, builds the CLI, and then runs it.
70
+
71
+ ```yaml
72
+ # Use these YAML anchors to setup common tasks
73
+ .oci_setup: &oci_setup |
74
+ curl -LO https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh
75
+ bash install.sh --accept-all-defaults
76
+ source ~/.bashrc
77
+
78
+ .clone_build_cli: &clone_build_cli |
79
+ git clone https://github.com/gtrevorrow/oci-token-exchange-action.git
80
+ cd oci-token-exchange-action
81
+ npm ci
82
+ npm run build:cli
83
+
84
+ deploy:
85
+ script:
86
+ # Install OCI CLI
87
+ - *oci_setup
88
+
89
+ # Clone and build the token exchange CLI
90
+ - *clone_build_cli
91
+
92
+ # Export token from GitLab CI
93
+ - export CI_JOB_JWT_V2="$(cat $CI_JOB_JWT_FILE)"
94
+
95
+ # Run the built CLI
96
+ - |
97
+ cd dist &&
98
+ PLATFORM=gitlab \
99
+ OIDC_CLIENT_ID=${OIDC_CLIENT_ID} \
100
+ DOMAIN_URL=${DOMAIN_URL} \
101
+ OCI_TENANCY=${OCI_TENANCY} \
102
+ OCI_REGION=${OCI_REGION} \
103
+ RETRY_COUNT=3 \
104
+ node cli.js
105
+
106
+ # Verify OCI CLI configuration works
107
+ - cd ../..
108
+ - oci os ns get
109
+
110
+ # Run only on main branch
111
+ rules:
112
+ - if: $CI_COMMIT_BRANCH == "main"
113
+
114
+ # Configure OIDC token for GitLab
115
+ id_tokens:
116
+ ID_TOKEN:
117
+ aud: https://cloud.oracle.com/gitlab
118
+ ```
119
+
120
+ #### Option 2: Using npm Package
121
+
122
+ This example installs the CLI tool directly from npm.
123
+
124
+ ```yaml
125
+ # Use these YAML anchors to setup common tasks
126
+ .oci_setup: &oci_setup |
127
+ curl -LO https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh
128
+ bash install.sh --accept-all-defaults
129
+ source ~/.bashrc
130
+
131
+ deploy_npm:
132
+ script:
133
+ # Install OCI CLI
134
+ - *oci_setup
135
+
136
+ # Install the token exchange CLI from npm
137
+ - npm install -g @gtrevorrow/oci-token-exchange
138
+
139
+ # Export token from GitLab CI
140
+ - export CI_JOB_JWT_V2="$(cat $CI_JOB_JWT_FILE)"
141
+
142
+ # Run the installed CLI
143
+ - |
144
+ PLATFORM=gitlab \
145
+ OIDC_CLIENT_ID=${OIDC_CLIENT_ID} \
146
+ DOMAIN_URL=${DOMAIN_URL} \
147
+ OCI_TENANCY=${OCI_TENANCY} \
148
+ OCI_REGION=${OCI_REGION} \
149
+ RETRY_COUNT=3 \
150
+ oci-token-exchange
151
+
152
+ # Verify OCI CLI configuration works
153
+ - oci os ns get
154
+
155
+ # Run only on main branch
156
+ rules:
157
+ - if: $CI_COMMIT_BRANCH == "main"
158
+
159
+ # Configure OIDC token for GitLab
160
+ id_tokens:
161
+ ID_TOKEN:
162
+ aud: https://cloud.oracle.com/gitlab
163
+ ```
164
+
165
+ ### Bitbucket Pipelines
166
+
167
+ #### Option 1: Building from Source
168
+
169
+ This example clones the repository, builds the CLI, and then runs it.
170
+
171
+ ```yaml
172
+ image: node:20
173
+
174
+ pipelines:
175
+ default:
176
+ - step:
177
+ name: Setup OCI CLI with OIDC Token Exchange (Build from Source)
178
+ oidc: true # Enable OIDC for Bitbucket
179
+ script:
180
+ # Setup OCI CLI
181
+ - curl -LO https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh
182
+ - bash install.sh --accept-all-defaults
183
+ - export PATH=$PATH:/root/bin
184
+
185
+ # Clone and build the token exchange CLI from GitHub
186
+ - git clone https://github.com/gtrevorrow/oci-token-exchange-action.git
187
+ - cd oci-token-exchange-action
188
+ - npm ci
189
+ - npm run build:cli
190
+
191
+ # Run the built CLI for token exchange
192
+ - >
193
+ cd dist &&
194
+ export PLATFORM=bitbucket &&
195
+ export OIDC_CLIENT_ID=${OIDC_CLIENT_ID} &&
196
+ export DOMAIN_URL=${DOMAIN_URL} &&
197
+ export OCI_TENANCY=${OCI_TENANCY} &&
198
+ export OCI_REGION=${OCI_REGION} &&
199
+ export RETRY_COUNT=3
200
+ - node cli.js || exit 1
201
+
202
+ # Verify OCI CLI works with generated token
203
+ - cd ../..
204
+ - oci os ns get
205
+
206
+ # Preserve credentials for subsequent steps
207
+ artifacts:
208
+ - ".oci/**"
209
+ - "private_key.pem"
210
+ - "public_key.pem"
211
+ - "session"
212
+ ```
213
+
214
+ #### Option 2: Using npm Package
215
+
216
+ This example installs the CLI tool directly from npm.
217
+
218
+ ```yaml
219
+ image: node:20
220
+
221
+ pipelines:
222
+ default:
223
+ - step:
224
+ name: Setup OCI CLI with OIDC Token Exchange (npm Package)
225
+ oidc: true # Enable OIDC for Bitbucket
226
+ script:
227
+ # Setup OCI CLI
228
+ - curl -LO https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh
229
+ - bash install.sh --accept-all-defaults
230
+ - export PATH=$PATH:/root/bin
231
+
232
+ # Install the token exchange CLI from npm
233
+ - npm install -g @gtrevorrow/oci-token-exchange
234
+
235
+ # Run the installed CLI for token exchange
236
+ - >
237
+ export PLATFORM=bitbucket &&
238
+ export OIDC_CLIENT_ID=${OIDC_CLIENT_ID} &&
239
+ export DOMAIN_URL=${DOMAIN_URL} &&
240
+ export OCI_TENANCY=${OCI_TENANCY} &&
241
+ export OCI_REGION=${OCI_REGION} &&
242
+ export RETRY_COUNT=3
243
+ - oci-token-exchange || exit 1
244
+
245
+ # Verify OCI CLI works with generated token
246
+ - oci os ns get
247
+
248
+ # Preserve credentials for subsequent steps
249
+ artifacts:
250
+ - ".oci/**"
251
+ - "private_key.pem"
252
+ - "public_key.pem"
253
+ - "session"
254
+ ```
255
+
256
+ ### Standalone CLI Usage
257
+ ```bash
258
+ # Install globally
259
+ npm install -g @gtrevorrow/oci-token-exchange
260
+
261
+ # Run with required environment variables
262
+ export LOCAL_OIDC_TOKEN="your.jwt.token"
263
+ PLATFORM=local \
264
+ OIDC_CLIENT_ID=your-client-id \
265
+ DOMAIN_URL=https://your-domain.identity.oraclecloud.com \
266
+ OCI_TENANCY=your-tenancy-ocid \
267
+ OCI_REGION=your-region \
268
+ oci-token-exchange
269
+
270
+ # Use the configured OCI CLI
271
+ oci os ns get
272
+ ```
273
+
274
+ ### Debugging
275
+
276
+ To enable detailed logging, set the `DEBUG` environment variable to `true`:
277
+
278
+ ```bash
279
+ export DEBUG=true
280
+ ```
281
+
282
+ This will log additional information, such as token exchange requests and responses, to help with troubleshooting.
283
+
284
+ ## Environment Variables / Github Secrets
285
+
286
+ The action supports flexible environment variable naming to make it easier to use across different platforms:
287
+
288
+ | Variable | Alternate Names | Description | Required |
289
+ |----------|----------------|-------------|----------|
290
+ | `OIDC_CLIENT_IDENTIFIER` | `INPUT_OIDC_CLIENT_IDENTIFIER` | OIDC client identifier | Yes |
291
+ | `DOMAIN_BASE_URL` | `INPUT_DOMAIN_BASE_URL` | Base URL of OCI Identity Domain | Yes |
292
+ | `OCI_TENANCY` | `INPUT_OCI_TENANCY` | OCI tenancy OCID | Yes |
293
+ | `OCI_REGION` | `INPUT_OCI_REGION` | OCI region identifier | Yes |
294
+ | `PLATFORM` | `INPUT_PLATFORM` | CI platform (`github`, `gitlab`, `bitbucket`, or `local`) | No (default: `github`) |
295
+ | `RETRY_COUNT` | `INPUT_RETRY_COUNT` | Number of retry attempts | No (default: `0`) |
296
+ | `LOCAL_OIDC_TOKEN` | - | OIDC token when using PLATFORM=local | Yes, when platform=local |
297
+ | `CI_JOB_JWT_V2` | - | GitLab CI JWT token | Yes, when platform=gitlab |
298
+ | `BITBUCKET_STEP_OIDC_TOKEN` | - | Bitbucket OIDC token | Yes, when platform=bitbucket |
299
+ | `DEBUG` | - | Enable debug output | No (default: `false`) |
300
+
301
+ ### Environment Variable Handling
302
+
303
+ Variables can be provided in two ways:
304
+
305
+ 1. **GitHub Actions Format**: Variables in the format `INPUT_VARIABLE_NAME` (used by GitHub Actions)
306
+ 2. **Standard Format**: Plain environment variables matching the exact names listed above
307
+
308
+ The GitHub Action automatically maps variables from GitHub's format to the standard format, but if you're using the CLI directly, use the variable names exactly as shown above.
309
+
310
+ ## How it Works
311
+
312
+ 1. Generates an RSA key pair
313
+ 2. Requests a GitHub OIDC JWT token
314
+ 3. Exchanges the JWT for an OCI UPST token
315
+ 4. Configures the OCI CLI with the obtained credentials
316
+
317
+ ## Semantic Versioning
318
+
319
+ This project uses [semantic-release](https://github.com/semantic-release/semantic-release) for automated versioning and publishing.
320
+ **For details on the build and release process, see [CONTRIBUTING.md](./CONTRIBUTING.md).**
321
+
322
+ ## License
323
+
324
+ This action is licensed under the [Universal Permissive License v1.0 (UPL-1.0)](LICENSE.txt).
325
+
326
+ ## Contributing
327
+
328
+ Contributions are welcome! Please feel free to submit a Pull Request.
329
+ ````
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const main_1 = require("./main");
5
+ // Map environment variables to GitHub Actions input format
6
+ // This mapping provides flexibility for users to follow different naming conventions
7
+ const envVarMappings = {
8
+ // Standard CLI env vars
9
+ PLATFORM: 'platform',
10
+ OIDC_CLIENT_IDENTIFIER: 'oidc_client_identifier',
11
+ DOMAIN_BASE_URL: 'domain_base_url',
12
+ OCI_TENANCY: 'oci_tenancy',
13
+ OCI_REGION: 'oci_region',
14
+ RETRY_COUNT: 'retry_count',
15
+ // Support for directly providing GitHub Actions style input vars
16
+ // This prevents needless remapping if already in correct format
17
+ INPUT_PLATFORM: 'platform',
18
+ INPUT_OIDC_CLIENT_IDENTIFIER: 'oidc_client_identifier',
19
+ INPUT_DOMAIN_BASE_URL: 'domain_base_url',
20
+ INPUT_OCI_TENANCY: 'oci_tenancy',
21
+ INPUT_OCI_REGION: 'oci_region',
22
+ INPUT_RETRY_COUNT: 'retry_count'
23
+ };
24
+ // Set environment variables in GitHub Actions format only if not already set
25
+ Object.entries(envVarMappings).forEach(([envVar, inputName]) => {
26
+ const value = process.env[envVar];
27
+ if (value && !process.env[`INPUT_${inputName.toUpperCase()}`]) {
28
+ process.env[`INPUT_${inputName.toUpperCase()}`] = value;
29
+ }
30
+ });
31
+ // Enable debug mode via environment variable
32
+ if (process.env.DEBUG === 'true') {
33
+ console.log('Debug mode enabled');
34
+ console.log('Environment variables mapped:');
35
+ Object.entries(envVarMappings).forEach(([envVar, inputName]) => {
36
+ if (process.env[envVar]) {
37
+ console.log(`${envVar} → INPUT_${inputName.toUpperCase()}`);
38
+ }
39
+ });
40
+ }
41
+ // Run the main function
42
+ (0, main_1.main)().catch(error => {
43
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
44
+ process.exit(1);
45
+ });
@@ -0,0 +1 @@
1
+ export * from './main';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./main"), exports);
package/dist/main.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { Platform } from './platforms/types';
2
+ import { TokenExchangeConfig, OciConfig, UpstTokenResponse, TokenExchangeError } from './types';
3
+ export declare function tokenExchangeJwtToUpst(platform: Platform, { tokenExchangeURL, clientCred, ociPublicKey, subjectToken, retryCount, currentAttempt }: TokenExchangeConfig): Promise<UpstTokenResponse>;
4
+ export declare function configureOciCli(platform: Platform, config: OciConfig): Promise<void>;
5
+ export declare function main(): Promise<void>;
6
+ export { TokenExchangeError, TokenExchangeConfig, OciConfig };
package/dist/main.js ADDED
@@ -0,0 +1,366 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.TokenExchangeError = void 0;
40
+ exports.tokenExchangeJwtToUpst = tokenExchangeJwtToUpst;
41
+ exports.configureOciCli = configureOciCli;
42
+ exports.main = main;
43
+ /**
44
+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates.
45
+ * Licensed under the Universal Permissive License v1.0 as shown at https://oss.oracle.com/licenses/upl.
46
+ */
47
+ const fs = __importStar(require("fs/promises"));
48
+ const path = __importStar(require("path"));
49
+ const crypto_1 = __importDefault(require("crypto"));
50
+ const axios_1 = __importDefault(require("axios"));
51
+ const github_1 = require("./platforms/github");
52
+ const cli_1 = require("./platforms/cli");
53
+ const types_1 = require("./types");
54
+ Object.defineProperty(exports, "TokenExchangeError", { enumerable: true, get: function () { return types_1.TokenExchangeError; } });
55
+ const PLATFORM_CONFIGS = {
56
+ github: {
57
+ audience: 'https://cloud.oracle.com'
58
+ },
59
+ gitlab: {
60
+ tokenEnvVar: 'CI_JOB_JWT_V2',
61
+ audience: 'https://cloud.oracle.com/gitlab'
62
+ },
63
+ bitbucket: {
64
+ tokenEnvVar: 'BITBUCKET_STEP_OIDC_TOKEN',
65
+ audience: 'https://cloud.oracle.com/bitbucket'
66
+ },
67
+ local: {
68
+ tokenEnvVar: 'LOCAL_OIDC_TOKEN',
69
+ audience: 'https://cloud.oracle.com'
70
+ }
71
+ };
72
+ // Create platform instance based on environment
73
+ function createPlatform(platformType) {
74
+ const config = PLATFORM_CONFIGS[platformType];
75
+ if (!config) {
76
+ throw new Error(`Unsupported platform: ${platformType}`);
77
+ }
78
+ return platformType === 'github' ? new github_1.GitHubPlatform() : new cli_1.CLIPlatform(config);
79
+ }
80
+ // Generate RSA key pair
81
+ const { publicKey, privateKey } = crypto_1.default.generateKeyPairSync('rsa', {
82
+ modulusLength: 2048
83
+ });
84
+ async function delay(count) {
85
+ return new Promise(resolve => setTimeout(resolve, 1000 * count));
86
+ }
87
+ // Encode public key in a format the OCI token exchange endpoint expects
88
+ function encodePublicKeyToBase64() {
89
+ return publicKey.export({ type: 'spki', format: 'der' }).toString('base64');
90
+ }
91
+ // Calculate the fingerprint of the OCI API public key
92
+ function calcFingerprint(publicKey) {
93
+ const publicKeyData = publicKey.export({ type: 'spki', format: 'der' });
94
+ const hash = crypto_1.default.createHash('MD5');
95
+ hash.update(publicKeyData);
96
+ return hash.digest('hex').replace(/(.{2})/g, '$1:').slice(0, -1);
97
+ }
98
+ // Function to validate URLs
99
+ function isValidUrl(url) {
100
+ try {
101
+ new URL(url);
102
+ return true;
103
+ }
104
+ catch (_) {
105
+ return false;
106
+ }
107
+ }
108
+ // Function to exchange JWT for OCI UPST token
109
+ async function tokenExchangeJwtToUpst(platform, { tokenExchangeURL, clientCred, ociPublicKey, subjectToken, retryCount, currentAttempt = 0 }) {
110
+ const headers = {
111
+ 'Content-Type': 'application/x-www-form-urlencoded',
112
+ 'Authorization': `Basic ${clientCred}`
113
+ };
114
+ if (subjectToken && platform.isDebug()) {
115
+ // Do some basic validation on the JWT token that we are going to exchange
116
+ try {
117
+ const parts = subjectToken.split('.');
118
+ // Check if the token is already a valid JWT (has at least 2 periods)
119
+ if (parts.length == 3) {
120
+ // If not well-formed, it might be a raw JWT that needs to be formatted
121
+ platform.logger.debug(' OIDC token does not appear to be a properly formatted JWT, attempting to parse');
122
+ }
123
+ else {
124
+ // Try to parse the token segments to validate it's a proper(ish) JWT
125
+ // Note: This is a very basic check and does not guarantee the token's validity
126
+ const header = JSON.parse(Buffer.from(parts[0], 'base64').toString());
127
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
128
+ platform.logger.debug(`JWT appears structured as expected with a header , payload and signature . Issuer: ${payload.iss || 'unknown'}`);
129
+ }
130
+ }
131
+ catch (error) {
132
+ platform.logger.warning(`Error pre-processing OIDC token: ${error instanceof Error ? error.message : 'Unknown error'}`);
133
+ // Continue with the original token, as we may be mistaken about its format
134
+ }
135
+ }
136
+ const data = {
137
+ 'grant_type': 'urn:ietf:params:oauth:grant-type:token-exchange',
138
+ 'requested_token_type': 'urn:oci:token-type:oci-upst',
139
+ 'public_key': ociPublicKey,
140
+ 'subject_token': subjectToken,
141
+ 'subject_token_type': 'jwt'
142
+ };
143
+ // Note that this will log potentially sensitive information but will leave it up to the user to decide if they want to enable debug logging with this risk
144
+ platform.logger.debug('Token Exchange Request Data: ' + JSON.stringify(data));
145
+ try {
146
+ const response = await axios_1.default.post(tokenExchangeURL, data, { headers });
147
+ platform.logger.debug('Token Exchange Response: ' + JSON.stringify(response.data));
148
+ return response.data; // auto wrapped in a Promise
149
+ }
150
+ catch (error) {
151
+ const attemptCounter = currentAttempt ? currentAttempt : 0;
152
+ if (retryCount > 0 && retryCount >= attemptCounter) {
153
+ platform.logger.warning(`Token exchange failed, retrying ... (${retryCount - attemptCounter - 1} retries left)`);
154
+ await delay(attemptCounter + 1);
155
+ return tokenExchangeJwtToUpst(platform, {
156
+ tokenExchangeURL,
157
+ clientCred,
158
+ ociPublicKey,
159
+ subjectToken: subjectToken,
160
+ retryCount,
161
+ currentAttempt: attemptCounter + 1
162
+ });
163
+ }
164
+ else {
165
+ platform.logger.error('Failed to exchange JWT for UPST after multiple attempts');
166
+ if (error instanceof Error) {
167
+ throw new types_1.TokenExchangeError(`Token exchange failed: ${error.message}`, error);
168
+ }
169
+ else {
170
+ throw new types_1.TokenExchangeError('Token exchange failed with an unknown error');
171
+ }
172
+ }
173
+ }
174
+ }
175
+ // Update configureOciCli to accept platform as first parameter
176
+ async function configureOciCli(platform, config) {
177
+ try {
178
+ const home = process.env.HOME || '';
179
+ if (!home) {
180
+ throw new types_1.TokenExchangeError('HOME environment variable is not defined');
181
+ }
182
+ // Sanitize file paths to prevent path injection
183
+ const ociConfigDir = path.resolve(path.join(home, '.oci'));
184
+ const ociConfigFile = path.resolve(path.join(ociConfigDir, 'config'));
185
+ const ociPrivateKeyFile = path.resolve(path.join(home, 'private_key.pem'));
186
+ const ociPublicKeyFile = path.resolve(path.join(home, 'public_key.pem'));
187
+ const upstTokenFile = path.resolve(path.join(home, 'session'));
188
+ platform.logger.debug(`OCI Config Dir: ${ociConfigDir}`);
189
+ const ociConfig = `[DEFAULT]
190
+ user='not used'
191
+ fingerprint=${config.ociFingerprint}
192
+ key_file=${ociPrivateKeyFile}
193
+ tenancy=${config.ociTenancy}
194
+ region=${config.ociRegion}
195
+ security_token_file=${upstTokenFile}
196
+ `;
197
+ try {
198
+ await fs.mkdir(ociConfigDir, { recursive: true });
199
+ }
200
+ catch (error) {
201
+ throw new Error('Unable to create OCI Config folder');
202
+ }
203
+ platform.logger.debug(`Created OCI Config : ${ociConfig}`);
204
+ try {
205
+ // Use await/try-catch for fs.access instead of chaining then/catch
206
+ try {
207
+ await fs.access(ociConfigFile);
208
+ platform.logger.warning(`Overwriting existing config file at ${ociConfigFile}`);
209
+ }
210
+ catch (e) {
211
+ // File does not exist, proceed silently
212
+ }
213
+ // Export and validate keys first
214
+ const privateKeyPem = config.privateKey.export({ type: 'pkcs1', format: 'pem' });
215
+ const publicKeyPem = config.publicKey.export({ type: 'spki', format: 'pem' });
216
+ if (!privateKeyPem || typeof privateKeyPem !== 'string') {
217
+ throw new Error('Private key export failed or invalid type');
218
+ }
219
+ if (!publicKeyPem || typeof publicKeyPem !== 'string') {
220
+ throw new Error('Public key export failed or invalid type');
221
+ }
222
+ if (!config.upstToken || typeof config.upstToken !== 'string') {
223
+ throw new Error('Session token is undefined or invalid type');
224
+ }
225
+ if (!ociConfig || typeof ociConfig !== 'string') {
226
+ throw new Error('OCI config is undefined or invalid type');
227
+ }
228
+ platform.logger.debug('Validated all file contents before writing');
229
+ await Promise.all([
230
+ fs.writeFile(ociConfigFile, ociConfig)
231
+ .then(() => platform.logger.debug(`Successfully wrote OCI config to ${ociConfigFile}`)),
232
+ fs.writeFile(ociPrivateKeyFile, privateKeyPem)
233
+ .then(() => fs.chmod(ociPrivateKeyFile, '600'))
234
+ .then(() => platform.logger.debug(`Successfully wrote private key to ${ociPrivateKeyFile} with permissions 600`)),
235
+ fs.writeFile(ociPublicKeyFile, publicKeyPem)
236
+ .then(() => platform.logger.debug(`Successfully wrote public key to ${ociPublicKeyFile}`)),
237
+ fs.writeFile(upstTokenFile, config.upstToken)
238
+ .then(() => fs.chmod(upstTokenFile, '600'))
239
+ .then(() => platform.logger.debug(`Successfully wrote session token to ${upstTokenFile}`))
240
+ ]);
241
+ }
242
+ catch (error) {
243
+ throw new types_1.TokenExchangeError('Failed to write OCI configuration files', error);
244
+ }
245
+ }
246
+ catch (error) {
247
+ platform.setFailed(`Failed to configure OCI CLI: ${error}`);
248
+ throw error;
249
+ }
250
+ }
251
+ // Update debugPrintJWTToken to properly handle different token formats
252
+ function debugPrintJWTToken(platform, token) {
253
+ if (platform.isDebug()) {
254
+ platform.logger.debug(`JWT Token received (length: ${token.length} characters)`);
255
+ try {
256
+ const tokenParts = token.split('.');
257
+ if (tokenParts.length !== 3) {
258
+ platform.logger.debug(`Warning: JWT token does not have the expected format (header.payload.signature)`);
259
+ return;
260
+ }
261
+ // Only decode and print the header and selected parts of payload, not the full token
262
+ const headerStr = Buffer.from(tokenParts[0], 'base64').toString('utf8');
263
+ let header;
264
+ try {
265
+ header = JSON.parse(headerStr);
266
+ platform.logger.debug(`JWT Header: ${JSON.stringify(header)}`);
267
+ }
268
+ catch (e) {
269
+ platform.logger.debug(`Failed to parse JWT header: ${headerStr}`);
270
+ }
271
+ // Parse payload but only log safe information
272
+ try {
273
+ const payloadStr = Buffer.from(tokenParts[1], 'base64').toString('utf8');
274
+ const payload = JSON.parse(payloadStr);
275
+ const safePayload = {
276
+ iss: payload.iss,
277
+ aud: payload.aud,
278
+ exp: payload.exp,
279
+ iat: payload.iat,
280
+ sub: payload.sub ? `${payload.sub.substring(0, 10)}...` : undefined,
281
+ // Include timestamp information for troubleshooting token expiry issues
282
+ expires_at: payload.exp ? new Date(payload.exp * 1000).toISOString() : undefined,
283
+ issued_at: payload.iat ? new Date(payload.iat * 1000).toISOString() : undefined
284
+ };
285
+ platform.logger.debug(`JWT Payload (safe parts): ${JSON.stringify(safePayload)}`);
286
+ }
287
+ catch (e) {
288
+ platform.logger.debug(`Failed to parse JWT payload: ${e instanceof Error ? e.message : 'Unknown error'}`);
289
+ }
290
+ platform.logger.debug(`JWT Signature present: ${tokenParts[2].length > 0 ? 'Yes' : 'No'}`);
291
+ }
292
+ catch (error) {
293
+ platform.logger.debug(`Error parsing JWT token: ${error instanceof Error ? error.message : 'Unknown error'}`);
294
+ }
295
+ }
296
+ }
297
+ // Main function now creates a local platform instance and passes it to subfunctions
298
+ async function main() {
299
+ const platformType = process.env.PLATFORM || 'github';
300
+ if (!PLATFORM_CONFIGS[platformType]) {
301
+ throw new Error(`Unsupported platform: ${platformType}`);
302
+ }
303
+ const platform = createPlatform(platformType);
304
+ try {
305
+ // Use typed object for config
306
+ const config = ['oidc_client_identifier', 'domain_base_url', 'oci_tenancy', 'oci_region']
307
+ .reduce((acc, input) => ({
308
+ ...acc,
309
+ [input]: platform.getInput(input, true)
310
+ }), {});
311
+ const retryCount = parseInt(platform.getInput('retry_count', false) || '0');
312
+ if (isNaN(retryCount) || retryCount < 0) {
313
+ throw new Error('retry_count must be a non-negative number');
314
+ }
315
+ // Validate the tokenExchangeURL
316
+ if (!isValidUrl(`${config.domain_base_url}/oauth2/v1/token`)) {
317
+ throw new Error('Invalid domain_base_url provided');
318
+ }
319
+ const idToken = await platform.getOIDCToken(PLATFORM_CONFIGS[platformType].audience);
320
+ platform.logger.debug(`Token obtained from ${platformType}`);
321
+ debugPrintJWTToken(platform, idToken);
322
+ // Calculate the fingerprint of the public key
323
+ const ociFingerprint = calcFingerprint(publicKey);
324
+ // Get the B64 encoded public key DER
325
+ const publicKeyB64 = encodePublicKeyToBase64();
326
+ platform.logger.debug(`Public Key B64: ${publicKeyB64}`);
327
+ //Exchange platform OIDC token for OCI UPST
328
+ const upstToken = await tokenExchangeJwtToUpst(platform, {
329
+ tokenExchangeURL: `${config.domain_base_url}/oauth2/v1/token`,
330
+ clientCred: Buffer.from(config.oidc_client_identifier).toString('base64'),
331
+ ociPublicKey: publicKeyB64,
332
+ subjectToken: idToken,
333
+ retryCount
334
+ });
335
+ platform.logger.info(`OCI issued a Session Token `);
336
+ //Setup the OCI cli/sdk on the CI platform runner with the UPST token
337
+ const ociConfig = {
338
+ privateKey,
339
+ publicKey,
340
+ upstToken: upstToken.token,
341
+ ociFingerprint,
342
+ ociTenancy: config.oci_tenancy,
343
+ ociRegion: config.oci_region
344
+ };
345
+ await configureOciCli(platform, ociConfig);
346
+ platform.logger.info(`OCI CLI has been configured to use the session token`);
347
+ // Add success output
348
+ platform.setOutput('configured', 'true');
349
+ // Error Handling
350
+ }
351
+ catch (error) {
352
+ if (error instanceof types_1.TokenExchangeError) {
353
+ platform.setFailed(`Token exchange failed: ${error.message}`);
354
+ if (error.cause) {
355
+ platform.logger.debug(`Cause: ${error.cause}`);
356
+ }
357
+ }
358
+ else {
359
+ platform.setFailed(`Action failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
360
+ }
361
+ throw error;
362
+ }
363
+ }
364
+ if (require.main === module) {
365
+ main();
366
+ }
@@ -0,0 +1,12 @@
1
+ import { Platform, PlatformLogger, PlatformConfig } from './types';
2
+ export declare class CLIPlatform implements Platform {
3
+ private config;
4
+ private readonly _logger;
5
+ constructor(config: PlatformConfig);
6
+ getInput(name: string, required?: boolean): string;
7
+ setOutput(name: string, value: string): void;
8
+ setFailed(message: string): void;
9
+ isDebug(): boolean;
10
+ getOIDCToken(audience: string): Promise<string>;
11
+ get logger(): PlatformLogger;
12
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CLIPlatform = void 0;
4
+ class CLIPlatform {
5
+ constructor(config) {
6
+ this.config = config;
7
+ this._logger = {
8
+ debug: (message) => { if (this.isDebug())
9
+ console.debug(message); },
10
+ info: (message) => console.log(message),
11
+ warning: (message) => console.warn(message),
12
+ error: (message) => console.error(message)
13
+ };
14
+ }
15
+ getInput(name, required = false) {
16
+ // Then check for direct environment variable (using common naming conventions)
17
+ const value = process.env[name.toUpperCase()] ||
18
+ process.env[`INPUT_${name.toUpperCase()}`] ||
19
+ process.env[`OCI_${name.toUpperCase()}`] ||
20
+ process.env[`OIDC_${name.toUpperCase()}`] || '';
21
+ if (required && !value) {
22
+ throw new Error(`Input required and not supplied: ${name}`);
23
+ }
24
+ return value;
25
+ }
26
+ setOutput(name, value) {
27
+ console.log(`::set-output name=${name}::${value}`);
28
+ }
29
+ setFailed(message) {
30
+ console.error(message);
31
+ process.exit(1);
32
+ }
33
+ isDebug() {
34
+ return process.env.DEBUG === 'true';
35
+ }
36
+ async getOIDCToken(audience) {
37
+ if (this.config.tokenEnvVar) {
38
+ const token = process.env[this.config.tokenEnvVar];
39
+ if (!token) {
40
+ throw new Error(`${this.config.tokenEnvVar} environment variable not found`);
41
+ }
42
+ // Do not log the token here
43
+ return token;
44
+ }
45
+ throw new Error('No OIDC token configuration available');
46
+ }
47
+ get logger() {
48
+ return this._logger;
49
+ }
50
+ }
51
+ exports.CLIPlatform = CLIPlatform;
@@ -0,0 +1,10 @@
1
+ import { Platform, PlatformLogger } from './types';
2
+ export declare class GitHubPlatform implements Platform {
3
+ private readonly _logger;
4
+ getInput(name: string, required?: boolean): string;
5
+ setOutput(name: string, value: string): void;
6
+ setFailed(message: string): void;
7
+ isDebug(): boolean;
8
+ getOIDCToken(audience: string): Promise<string>;
9
+ get logger(): PlatformLogger;
10
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.GitHubPlatform = void 0;
37
+ const core = __importStar(require("@actions/core"));
38
+ class GitHubPlatform {
39
+ constructor() {
40
+ this._logger = {
41
+ debug: (message) => core.debug(message),
42
+ info: (message) => core.info(message),
43
+ warning: (message) => core.warning(message),
44
+ error: (message) => core.error(message)
45
+ };
46
+ }
47
+ getInput(name, required = false) {
48
+ return core.getInput(name, { required });
49
+ }
50
+ setOutput(name, value) {
51
+ core.setOutput(name, value);
52
+ }
53
+ setFailed(message) {
54
+ core.setFailed(message);
55
+ }
56
+ isDebug() {
57
+ return core.isDebug();
58
+ }
59
+ async getOIDCToken(audience) {
60
+ const token = await core.getIDToken(audience);
61
+ if (!token) {
62
+ throw new Error('Failed to get OIDC token from GitHub Actions');
63
+ }
64
+ return token;
65
+ }
66
+ get logger() {
67
+ return this._logger;
68
+ }
69
+ }
70
+ exports.GitHubPlatform = GitHubPlatform;
@@ -0,0 +1,18 @@
1
+ export interface PlatformLogger {
2
+ debug(message: string): void;
3
+ info(message: string): void;
4
+ warning(message: string): void;
5
+ error(message: string): void;
6
+ }
7
+ export interface Platform {
8
+ getInput(name: string, required?: boolean): string;
9
+ setOutput(name: string, value: string): void;
10
+ setFailed(message: string): void;
11
+ isDebug(): boolean;
12
+ logger: PlatformLogger;
13
+ getOIDCToken(audience: string): Promise<string>;
14
+ }
15
+ export interface PlatformConfig {
16
+ tokenEnvVar?: string;
17
+ audience: string;
18
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,89 @@
1
+ import crypto from 'crypto';
2
+ /**
3
+ * Configuration for token exchange operation
4
+ */
5
+ export interface TokenExchangeConfig {
6
+ /**
7
+ * URL of the token exchange endpoint
8
+ */
9
+ tokenExchangeURL: string;
10
+ /**
11
+ * Base64-encoded client credentials
12
+ */
13
+ clientCred: string;
14
+ /**
15
+ * Base64-encoded DER format of the OCI public key
16
+ */
17
+ ociPublicKey: string;
18
+ /**
19
+ * JWT token to be exchanged
20
+ */
21
+ subjectToken: string;
22
+ /**
23
+ * Number of retry attempts for token exchange
24
+ */
25
+ retryCount: number;
26
+ /**
27
+ * Current attempt number (used internally for retries)
28
+ */
29
+ currentAttempt?: number;
30
+ }
31
+ /**
32
+ * Configuration for the OCI CLI setup
33
+ */
34
+ export interface OciConfig {
35
+ /**
36
+ * Private key used for OCI authentication
37
+ */
38
+ privateKey: crypto.KeyObject;
39
+ /**
40
+ * Public key used for OCI authentication
41
+ */
42
+ publicKey: crypto.KeyObject;
43
+ /**
44
+ * User principal security token obtained from token exchange
45
+ */
46
+ upstToken: string;
47
+ /**
48
+ * Fingerprint of the public key
49
+ */
50
+ ociFingerprint: string;
51
+ /**
52
+ * OCI tenancy OCID
53
+ */
54
+ ociTenancy: string;
55
+ /**
56
+ * OCI region identifier
57
+ */
58
+ ociRegion: string;
59
+ }
60
+ /**
61
+ * Input configuration for the CLI/Action
62
+ */
63
+ export interface ConfigInputs {
64
+ oidc_client_identifier: string;
65
+ domain_base_url: string;
66
+ oci_tenancy: string;
67
+ oci_region: string;
68
+ }
69
+ /**
70
+ * Response from token exchange operation
71
+ */
72
+ export interface UpstTokenResponse {
73
+ /**
74
+ * The exchanged UPST token
75
+ */
76
+ token: string;
77
+ }
78
+ /**
79
+ * Custom error class for token exchange errors
80
+ */
81
+ export declare class TokenExchangeError extends Error {
82
+ readonly cause?: unknown | undefined;
83
+ /**
84
+ * Creates a new TokenExchangeError
85
+ * @param message Error message
86
+ * @param cause Underlying cause of the error
87
+ */
88
+ constructor(message: string, cause?: unknown | undefined);
89
+ }
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TokenExchangeError = void 0;
4
+ /**
5
+ * Custom error class for token exchange errors
6
+ */
7
+ class TokenExchangeError extends Error {
8
+ /**
9
+ * Creates a new TokenExchangeError
10
+ * @param message Error message
11
+ * @param cause Underlying cause of the error
12
+ */
13
+ constructor(message, cause) {
14
+ super(message);
15
+ this.cause = cause;
16
+ this.name = 'TokenExchangeError';
17
+ }
18
+ }
19
+ exports.TokenExchangeError = TokenExchangeError;
package/package.json ADDED
@@ -0,0 +1,110 @@
1
+ {
2
+ "name": "@gtrevorrow/oci-token-exchange",
3
+ "description": "OCI Usder Principal Token Exchange for GitHub Actions, GitLab CI, and Bitbucket Pipelines",
4
+ "version": "1.0.0-20250417-beta",
5
+ "author": {
6
+ "name": "Oracle Cloud Infrastructure",
7
+ "email": "gordon.trevorrow@oracle.com"
8
+ },
9
+ "private": false,
10
+ "homepage": "https://github.com/gtrevorrow/oci-token-exchange-action/blob/README.md",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/gtrevorrow/oci-token-exchange-action.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/gtrevorrow/oci-token-exchange-action/issues"
17
+ },
18
+ "keywords": [
19
+ "github",
20
+ "actions",
21
+ "oracle-cloud",
22
+ "oracle-cloud-infrastructure"
23
+ ],
24
+ "exports": {
25
+ ".": "./dist/main.js"
26
+ },
27
+ "bin": {
28
+ "oci-token-exchange": "./dist/cli.js"
29
+ },
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "bundle": "npm run format:write && npm run package",
36
+ "format:write": "npx prettier --write .",
37
+ "format:check": "npx prettier --check .",
38
+ "lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
39
+ "package": "npx ncc build src/index.ts -o dist --source-map --license LICENSE.txt",
40
+ "all": "npm run format:write && npm run lint && npm run package",
41
+ "test": "jest",
42
+ "build:cli": "tsc && chmod +x dist/cli.js",
43
+ "package:cli": "npm run build:cli && npm pack",
44
+ "prepare": "husky install",
45
+ "release": "semantic-release",
46
+ "commit": "cz"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "LICENSE.txt",
51
+ "README.md"
52
+ ],
53
+ "license": "UPL-1.0",
54
+ "dependencies": {
55
+ "@actions/core": "^1.11.1",
56
+ "@actions/exec": "^1.1.1",
57
+ "@actions/github": "^6.0.0",
58
+ "@actions/io": "^1.1.3",
59
+ "@actions/tool-cache": "^2.0.2",
60
+ "axios": "^1.8.4"
61
+ },
62
+ "devDependencies": {
63
+ "@commitlint/cli": "^19.8.0",
64
+ "@commitlint/config-conventional": "^19.8.0",
65
+ "@semantic-release/changelog": "^6.0.3",
66
+ "@semantic-release/git": "^10.0.1",
67
+ "@types/jest": "^29.5.13",
68
+ "@types/node": "^20.17.11",
69
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
70
+ "@typescript-eslint/parser": "^7.18.0",
71
+ "@vercel/ncc": "^0.38.1",
72
+ "commitizen": "^4.3.0",
73
+ "cz-conventional-changelog": "^3.3.0",
74
+ "eslint": "^8.57.1",
75
+ "eslint-config-prettier": "^9.1.0",
76
+ "eslint-plugin-prettier": "^5.2.1",
77
+ "husky": "^8.0.0",
78
+ "jest": "^29.7.0",
79
+ "list": "^2.0.19",
80
+ "npm": "^11.0.0",
81
+ "prettier": "^3.3.3",
82
+ "prettier-eslint": "^16.3.0",
83
+ "semantic-release": "^22.0.0",
84
+ "test-jest": "^1.0.1",
85
+ "ts-jest": "^29.2.5",
86
+ "typescript": "^5.8.2",
87
+ "typescript-eslint": "^8.1.0"
88
+ },
89
+ "publishConfig": {
90
+ "access": "public"
91
+ },
92
+ "release": {
93
+ "branches": [
94
+ "main"
95
+ ],
96
+ "plugins": [
97
+ "@semantic-release/commit-analyzer",
98
+ "@semantic-release/release-notes-generator",
99
+ "@semantic-release/changelog",
100
+ "@semantic-release/npm",
101
+ "@semantic-release/github",
102
+ "@semantic-release/git"
103
+ ]
104
+ },
105
+ "config": {
106
+ "commitizen": {
107
+ "path": "cz-conventional-changelog"
108
+ }
109
+ }
110
+ }