├── .github └── workflows │ └── demo.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── action.yml ├── cleanup.js ├── dist ├── cleanup.js └── index.js ├── index.js ├── package.json ├── paths.js ├── scripts └── build.js └── yarn.lock /.github/workflows/demo.yml: -------------------------------------------------------------------------------- 1 | on: [ push, pull_request ] 2 | 3 | jobs: 4 | deployment_keys_demo: 5 | strategy: 6 | fail-fast: false 7 | matrix: 8 | os: [ ubuntu-latest, macOS-latest, windows-latest ] 9 | runs-on: ${{ matrix.os }} 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Setup key 13 | uses: ./ 14 | with: 15 | ssh-private-key: | 16 | ${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }} 17 | ${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }} 18 | - run: | 19 | git clone https://github.com/mpdude/test-1.git test-1-http 20 | git clone git@github.com:mpdude/test-1.git test-1-git 21 | git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh 22 | git clone https://github.com/mpdude/test-2.git test-2-http 23 | git clone git@github.com:mpdude/test-2.git test-2-git 24 | git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh 25 | 26 | docker_demo: 27 | runs-on: ubuntu-latest 28 | container: 29 | image: ubuntu:latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | - run: apt update && apt install -y openssh-client git 33 | - name: Setup key 34 | uses: ./ 35 | with: 36 | ssh-private-key: | 37 | ${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }} 38 | ${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }} 39 | - run: | 40 | git clone https://github.com/mpdude/test-1.git test-1-http 41 | git clone git@github.com:mpdude/test-1.git test-1-git 42 | git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh 43 | git clone https://github.com/mpdude/test-2.git test-2-http 44 | git clone git@github.com:mpdude/test-2.git test-2-git 45 | git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh 46 | 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## v0.9.1 [2024-03-17] 11 | 12 | ### Fixed 13 | 14 | * Fix path used to execute ssh-agent in cleanup.js to respect custom paths set by input (#235) 15 | 16 | ## v0.9.0 [2024-02-06] 17 | 18 | ### Changed 19 | 20 | * Update all versions of `actions/checkout` to v4 (#199) 21 | * Update to Node 20 (#201) 22 | 23 | ## v0.8.0 [2023-03-24] 24 | 25 | ### Changed 26 | 27 | * No longer writing GitHub's SSH host keys to `known_hosts` (#171) 28 | * Update to actions/checkout@v3 (#143) 29 | * Allow the user to override the commands for git, ssh-agent, and ssh-add (#154) 30 | 31 | ## v0.7.0 [2022-10-19] 32 | 33 | ### Added 34 | 35 | * Add the `log-public-key` input that can be used to turn off logging key identities (#122) 36 | 37 | ### Fixed 38 | 39 | * Fix path to `git` binary on Windows, assuming GitHub-hosted runners (#136, #137) 40 | * Fix a nonsensical log message (#139) 41 | 42 | ## v0.6.0 [2022-10-19] 43 | 44 | ### Changed 45 | 46 | * Update the version of Node used by the action from 12 to 16 (https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/). 47 | 48 | ## v0.5.4 [2021-11-21] 49 | 50 | ### Fixed 51 | 52 | * Update changed GitHub Host Keys (#102, #101) 53 | 54 | ### Changed 55 | 56 | * Various documentation (README) improvements and additions 57 | * Change logging to more precisely state that _public_ keys are being printed 58 | 59 | ## v0.5.3 [2021-06-11] 60 | 61 | ### Fixed 62 | 63 | * Fixed cleanup phase to really terminate the ssh-agent (#80) 64 | * Fix termination of ssh-agent also on workflow failure (#79) 65 | 66 | ### Changed 67 | 68 | * Various documentation (README) improvements and additions 69 | 70 | ## v0.5.2 [2021-04-07] 71 | 72 | ### Fixed 73 | 74 | * Use case-insensitive regex matching when scanning key comments (#68, #70, #71) 75 | 76 | ### Changed 77 | 78 | * Log when a key is _not_ used as a deploy key (#69) 79 | 80 | ## v0.5.1 [2021-03-10] 81 | 82 | ### Fixed 83 | 84 | * Fix deployment key mapping on Windows virtual environment by using SSH binaries from the Git 85 | suite, terminate ssh-agent upon actio termination on Windows as well (#63) 86 | * Handle ENOENT exceptions with a graceful message 87 | 88 | ### Changed 89 | 90 | * Various documentation (README) improvements and additions 91 | 92 | ## v0.5.0 [2021-02-19] 93 | 94 | ### Added 95 | 96 | * Add support for GitHub Deployment Keys through key comments (#59). Fixes #30, closes #38. 97 | * Support for container-based workflows and Windows (#17) 98 | 99 | ### Fixed 100 | 101 | * Fix scripts/build.js to work on Windows (#38) 102 | 103 | ### Changed 104 | 105 | * Various documentation (README) improvements and additions 106 | 107 | ## v0.4.1 [2020-10-07] 108 | 109 | ### Fixed 110 | 111 | * This action no longer relies on `set-env`, which has been deprecated. 112 | 113 | ## v0.4.0 114 | 115 | ### Changed 116 | 117 | * A failure to kill the agent in the post-action step will no longer fail the workflow run. That way, you can kill the agent yourself when necessary (#33). 118 | 119 | ## v0.3.0 [2020-05-18] 120 | 121 | ### Added 122 | 123 | * A new post-action step will automatically clean up the running agent at the end of a job. This helps with self-hosted runners, which are non-ephemeral. (@thommyhh, #27) 124 | 125 | ### Changed 126 | 127 | * Unless the SSH_AUTH_SOCK is configured explicitly, the SSH agent will now use a random file name for the socket. That way, multiple, concurrent SSH agents can be used on self-hosted runners. (@thommyhh, #27) 128 | 129 | ## v0.2.0 [2020-01-14] 130 | 131 | ### Added 132 | 133 | * Multiple SSH keys can now be provided (#14, closes #7). Thanks to 134 | @webknjaz and @bradmartin for support and tests. 135 | 136 | * Catch empty ssh-private-key input values and exit with a helpful 137 | error message right away. 138 | 139 | ## v0.1.0 [2019-09-15] 140 | 141 | Initial release. 142 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 webfactory GmbH 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `ssh-agent` GitHub Action 2 | 3 | This action 4 | * starts the `ssh-agent`, 5 | * exports the `SSH_AUTH_SOCK` environment variable, and 6 | * loads one or several private SSH key into the agent. 7 | 8 | It should work in all GitHub Actions virtual environments, including container-based workflows. 9 | 10 | Windows and Docker support is, however, somewhat new. Since we have little feedback from the field, things might not run so smooth for you as we'd hope. If Windows and/or Docker-based workflows work well for you, leave a :+1: at https://github.com/webfactory/ssh-agent/pull/17. 11 | 12 | Also, using multiple GitHub deployment keys is supported; keys are mapped to repositories by using SSH key comments (see below). 13 | 14 | ## Why? 15 | 16 | When running a GitHub Action workflow to stage your project, run tests or build images, you might need to fetch additional libraries or _vendors_ from private repositories. 17 | 18 | GitHub Actions only have access to the repository they run for. So, in order to access additional private repositories, create an SSH key with sufficient access privileges. Then, use this action to make the key available with `ssh-agent` on the Action worker node. Once this has been set up, `git clone` commands using `ssh` URLs will _just work_. Also, running `ssh` commands to connect to other servers will be able to use the key. 19 | 20 | ## Usage 21 | 22 | 1. Generate a new SSH key with sufficient access privileges. For security reasons, don't use your personal SSH key but set up a dedicated one for use in GitHub Actions. See below for a few hints if you are unsure about this step. 23 | 2. Make sure you don't have a passphrase set on the private key. 24 | 3. Add the public SSH key to the private repository you are pulling from during the Github Action as a 'Deploy Key'. 25 | 4. Add the private SSH key to the repository triggering the Github Action: 26 | * In your repository, go to the *Settings > Secrets* menu and create a new secret. In this example, we'll call it `SSH_PRIVATE_KEY`. 27 | * Put the contents of the *private* SSH key file into the contents field.
28 | * This key should start with `-----BEGIN ... PRIVATE KEY-----`, consist of many lines and ends with `-----END ... PRIVATE KEY-----`. 29 | 5. In your workflow definition file, add the following step. Preferably this would be rather on top, near the `actions/checkout@v4` line. 30 | 31 | ```yaml 32 | # .github/workflows/my-workflow.yml 33 | jobs: 34 | my_job: 35 | ... 36 | steps: 37 | - uses: actions/checkout@v4 38 | # Make sure the @v0.9.0 matches the current version of the action 39 | - uses: webfactory/ssh-agent@v0.9.0 40 | with: 41 | ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} 42 | # ... other steps 43 | ``` 44 | 5. If, for some reason, you need to change the location of the SSH agent socket, you can use the `ssh-auth-sock` input to provide a path. 45 | 46 | ### Using Multiple Keys 47 | 48 | There are cases where you might need to use multiple keys. For example, "[deploy keys](https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys)" might be limited to a single repository, so you'll need several of them. 49 | 50 | You can set up different keys as different secrets and pass them all to the action like so: 51 | 52 | ```yaml 53 | # ... contents as before 54 | - uses: webfactory/ssh-agent@v0.9.0 55 | with: 56 | ssh-private-key: | 57 | ${{ secrets.FIRST_KEY }} 58 | ${{ secrets.NEXT_KEY }} 59 | ${{ secrets.ANOTHER_KEY }} 60 | ``` 61 | 62 | The `ssh-agent` will load all of the keys and try each one in order when establishing SSH connections. 63 | 64 | There's one **caveat**, though: SSH servers may abort the connection attempt after a number of mismatching keys have been presented. So if, for example, you have six different keys loaded into the `ssh-agent`, but the server aborts after five unknown keys, the last key (which might be the right one) will never even be tried. But when you're using GitHub Deploy Keys, read on! 65 | 66 | ### Support for GitHub Deploy Keys 67 | 68 | When using **Github deploy keys**, GitHub servers will accept the _first_ known key. But since deploy keys are scoped to a single repository, this might not be the key needed to access a particular repository. Thus, you will get the error message `fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.` if the wrong key/repository combination is tried. 69 | 70 | To support picking the right key in this use case, this action scans _key comments_ and will set up extra Git and SSH configuration to make things work. 71 | 72 | 1. When creating the deploy key for a repository like `git@github.com:owner/repo.git` or `https://github.com/owner/repo`, put that URL into the key comment. (Hint: Try `ssh-keygen ... -C "git@github.com:owner/repo.git"`.) 73 | 2. After keys have been added to the agent, this action will scan the key comments. 74 | 3. For key comments containing such URLs, a Git config setting is written that uses [`url..insteadof`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf). It will redirect `git` requests to URLs starting with either `https://github.com/owner/repo` or `git@github.com:owner/repo` to a fake hostname/URL like `git@...some.hash...:owner/repo`. 75 | 4. An SSH configuration section is generated that applies to the fake hostname. It will map the SSH connection back to `github.com`, while at the same time pointing SSH to a file containing the appropriate key's public part. That will make SSH use the right key when connecting to GitHub.com. 76 | 77 | ## Action Inputs 78 | 79 | The following inputs can be used to control the action's behavior: 80 | 81 | * `ssh-private-key`: Required. Use this to provide the key(s) to load as GitHub Actions secrets. 82 | * `ssh-auth-sock`: Can be used to control where the SSH agent socket will be placed. Ultimately affects the `$SSH_AUTH_SOCK` environment variable. 83 | * `log-public-key`: Set this to `false` if you want to suppress logging of _public_ key information. To simplify debugging and since it contains public key information only, this is turned on by default. 84 | * `ssh-agent-cmd`: Optional. Use this to specify a custom location for the `ssh-agent` binary. 85 | * `ssh-add-cmd`: Optional. Use this to specify a custom location for the `ssh-add` binary. 86 | * `git-cmd`: Optional. Use this to specify a custom location for the `git` binary. 87 | 88 | ## Exported variables 89 | 90 | The action exports the `SSH_AUTH_SOCK` and `SSH_AGENT_PID` environment variables through the Github Actions core module. 91 | The `$SSH_AUTH_SOCK` is used by several applications like git or rsync to connect to the SSH authentication agent. 92 | The `$SSH_AGENT_PID` contains the process id of the agent. This is used to kill the agent in post job action. 93 | 94 | ## Known Issues and Limitations 95 | 96 | ### Works for the Current Job Only 97 | 98 | Since each job [runs in a fresh instance](https://help.github.com/en/articles/about-github-actions#job) of the virtual environment, the SSH key will only be available in the job where this action has been referenced. You can, of course, add the action in multiple jobs or even workflows. All instances can use the same `SSH_PRIVATE_KEY` secret. 99 | 100 | ### SSH Private Key Format 101 | 102 | If the private key is not in the `PEM` format, you will see an `Error loading key "(stdin)": invalid format` message. 103 | 104 | Use `ssh-keygen -p -f path/to/your/key -m pem` to convert your key file to `PEM`, but be sure to make a backup of the file first 😉. 105 | 106 | ## Additional Information for Particular Tools or Platforms 107 | 108 | If you know that your favorite tool or platform of choice requires extra tweaks or has some caveats when running with SSH, feel free to open a PR to amend this section here. 109 | 110 | ### Container-based Workflows 111 | 112 | If you are using this action on container-based workflows, make sure the container has the necessary SSH binaries or package(s) installed. 113 | 114 | ### Building Docker Images and/or Using the `docker/build-push-action` Action 115 | 116 | When you are building Docker images with `docker build` or `docker compose build` and need to provide the SSH keys to the build, don't forget to pass `--ssh default=${{ env.SSH_AUTH_SOCK }}` on the command line to pass the SSH agent socket through. See the [Docker documentation](https://docs.docker.com/engine/reference/commandline/buildx_build/#ssh) for more information on this option. 117 | 118 | If you are using the `docker/build-push-action`, you can do so by adding the following config. 119 | 120 | ```yml 121 | - name: Build and push 122 | id: docker_build 123 | uses: docker/build-push-action@v2 124 | with: 125 | ssh: | 126 | default=${{ env.SSH_AUTH_SOCK }} 127 | ``` 128 | 129 | Make sure not to miss the next section, though. 130 | 131 | ### Using Multiple Deploy Keys Inside Docker Builds 132 | 133 | When you pass the SSH agent socket to the Docker build environment _and_ want to use multiple GitHub deploy keys, you need to copy the Git and SSH configuration files to the build environment as well. This is necessary _in addition to_ forwarding the SSH agent socket into the build process. The config files are required so that Git can pick the right one from your deployment keys. 134 | 135 | This requires an additional step in the workflow file **after** the `ssh-agent` step and **before** the Docker build step. You also need two additional lines in the `Dockerfile` to actually copy the configs. 136 | 137 | The following example will: 138 | * collect the necessary Git and SSH configuration files in a directory that must be part of the Docker build context so that... 139 | * ... the files can be copied into the Docker image (or an intermediate build stage). 140 | 141 | Workflow: 142 | 143 | ```yml 144 | - name: ssh-agent setup 145 | ... 146 | 147 | - name: Collect Git and SSH config files in a directory that is part of the Docker build context 148 | run: | 149 | mkdir root-config 150 | cp -r ~/.gitconfig ~/.ssh root-config/ 151 | 152 | - name: Docker build 153 | # build-push-action | docker [compose] build | etc. 154 | ... 155 | ``` 156 | 157 | Dockerfile: 158 | 159 | ```Dockerfile 160 | # Copy the two files in place and fix different path/locations inside the Docker image 161 | COPY root-config /root/ 162 | RUN sed 's|/home/runner|/root|g' -i.bak /root/.ssh/config 163 | ``` 164 | 165 | Keep in mind that the resulting Docker image now might contain these customized Git and SSH configuration files! Your private SSH keys are never written to files anywhere, just loaded into the SSH agent and forwarded into the container. The config files might, however, give away details about your build or development process and contain the names and URLs of your (private) repositories. You might want to use a multi-staged build to make sure these files do not end up in the final image. 166 | 167 | If you still get the error message: `fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.`, you most likely forgot one of the steps above. 168 | 169 | ### Cargo's (Rust) Private Dependencies on Windows 170 | 171 | If you are using private repositories in your dependencies like this: 172 | 173 | ``` 174 | stuff = { git = "ssh://git@github.com/myorg/stuff.git", branch = "main" } 175 | ``` 176 | 177 | ... you will need to change a configuration in the workflow for Windows machines in order to make cargo able to clone private repositories. 178 | 179 | There are 2 ways you can achieve this: 180 | 181 | 1. Add this step once in your job **before** any cargo command: 182 | 183 | ``` 184 | - name: Update cargo config to use Git CLI 185 | run: Set-Content -Path $env:USERPROFILE\.cargo\config.toml "[net]`ngit-fetch-with-cli = true" 186 | ``` 187 | 188 | This will configure Cargo to use the Git CLI as explained in the [Cargo's documentation](https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli). 189 | 190 | 2. Alternatively you can set it to the environment variables for the entire workflow: 191 | 192 | ``` 193 | env: 194 | CARGO_NET_GIT_FETCH_WITH_CLI: true 195 | ``` 196 | 197 | ### Using Deploy Keys with Swift Package Manager 198 | 199 | `xcodebuild` by default uses Xcode's built-in Git tooling. If you want to use GitHub Deploy Keys as supported by this action, however, that version of Git will lack the necessary URL remapping. In this case, pass `-scmProvider system` to the `xcodebuild` command, as mentioned in [Apple's documentation](https://developer.apple.com/documentation/swift_packages/building_swift_packages_or_apps_that_use_them_in_continuous_integration_workflows#3680255). 200 | 201 | ## What this Action *cannot* do for you 202 | 203 | The following items are not issues, but beyond what this Action is supposed to do. 204 | 205 | ### Work on Remote Machines 206 | 207 | When using `ssh` to connect from the GitHub Action worker node to another machine, you *can* forward the SSH Agent socket and use your private key on the other (remote) machine. However, this Action will not configure `known_hosts` or other SSH settings on the remote machine for you. 208 | 209 | ### Provide the SSH Key as a File 210 | 211 | This Action is designed to pass the SSH key directly into `ssh-agent`; that is, the key is available in memory on the GitHub Action worker node, but never written to disk. As a consequence, you _cannot_ pass the key as a build argument or a mounted file into Docker containers that you build or run on the worker node. You _can_, however, mount the `ssh-agent` Unix socket into a Docker container that you _run_, set up the `SSH_AUTH_SOCK` env var and then use SSH from within the container (see https://github.com/webfactory/ssh-agent/issues/11). 212 | 213 | ### Run `ssh-keyscan` to Add Host Keys for Additional Hosts 214 | 215 | If you want to use `ssh-keyscan` to add additional hosts (that you own/know) to the `known_hosts` file, you can do so with a single shell line in your Action definition. You don't really need this Action to do this for you. 216 | 217 | As a side note, using `ssh-keyscan` without proper key verification is susceptible to man-in-the-middle attacks. You might prefer putting your _known_ SSH host key in your own Action files to add it to the `known_hosts` file. The SSH host key is not secret and can safely be committed into the repo. 218 | 219 | ## Creating SSH Keys 220 | 221 | In order to create a new SSH key, run `ssh-keygen -t ed25519 -a 100 -f path/to/keyfile`, as suggested in [this blog post](https://stribika.github.io/2015/01/04/secure-secure-shell.html). 222 | If you need to work with some older server software and need RSA keys, try `ssh-keygen -t rsa -b 4096 -o -f path/to/keyfile` instead. 223 | 224 | Both commands will prompt you for a key passphrase and save the key in `path/to/keyfile`. 225 | In general, having a passphrase is a good thing, since it will keep the key encrypted on your disk. When using the key with this action, however, you need to make sure you don't 226 | specify a passphrase: The key must be usable without reading the passphrase from input. Since the key itself is stored using GitHub's "Secret" feature, it should be fairly safe anyway. 227 | 228 | ## Authorizing a Key 229 | 230 | To actually grant the SSH key access, you can – on GitHub – use at least two ways: 231 | 232 | * [Deploy keys](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys) can be added to individual GitHub repositories. They can give read and/or write access to the particular repository. When pulling a lot of dependencies, however, you'll end up adding the key in many places. Rotating the key probably becomes difficult. The deploy key needs to be added to the private repository that is being fetched as a private dependency. 233 | 234 | * A [machine user](https://developer.github.com/v3/guides/managing-deploy-keys/#machine-users) can be used for more fine-grained permissions management and have access to multiple repositories with just one instance of the key being registered. It will, however, count against your number of users on paid GitHub plans. 235 | 236 | ## Hacking 237 | 238 | As a note to my future self, in order to work on this repo: 239 | 240 | * Clone it 241 | * Run `yarn install` to fetch dependencies 242 | * _hack hack hack_ 243 | * `node index.js`. Inputs are passed through `INPUT_` env vars with their names uppercased. 244 | 245 | On *nix use: 246 | ```bash 247 | env "INPUT_SSH-PRIVATE-KEY=\`cat file\`" node index.js 248 | ``` 249 | 250 | On Windows (cmd): 251 | ```cmd 252 | set /P INPUT_SSH-PRIVATE-KEY=< file 253 | node index.js 254 | ``` 255 | 256 | On Windows (PowerShell): 257 | ```ps 258 | ${env:INPUT_SSH-PRIVATE-KEY} = (Get-Content .\test-keys -Raw); node index.js 259 | node index.js 260 | ``` 261 | * Run `npm run build` to update `dist/*`, which holds the files actually run 262 | * Read https://help.github.com/en/articles/creating-a-javascript-action if unsure. 263 | * Maybe update the README example when publishing a new version. 264 | 265 | ## Credits, Copyright and License 266 | 267 | This action was written by webfactory GmbH, Bonn, Germany. We're a software development 268 | agency with a focus on PHP (mostly [Symfony](http://github.com/symfony/symfony)). If you're a 269 | developer looking for new challenges, we'd like to hear from you! 270 | 271 | - 272 | - 273 | 274 | Copyright 2019 – 2023 webfactory GmbH, Bonn. Code released under [the MIT license](LICENSE). 275 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: 'webfactory/ssh-agent' 2 | description: 'Run `ssh-agent` and load an SSH key to access other private repositories' 3 | inputs: 4 | ssh-private-key: 5 | description: 'Private SSH key to register in the SSH agent' 6 | required: true 7 | ssh-auth-sock: 8 | description: 'Where to place the SSH Agent auth socket' 9 | log-public-key: 10 | description: 'Whether or not to log public key fingerprints' 11 | required: false 12 | default: true 13 | ssh-agent-cmd: 14 | description: 'ssh-agent command' 15 | required: false 16 | ssh-add-cmd: 17 | description: 'ssh-add command' 18 | required: false 19 | git-cmd: 20 | description: 'git command' 21 | required: false 22 | runs: 23 | using: 'node20' 24 | main: 'dist/index.js' 25 | post: 'dist/cleanup.js' 26 | post-if: 'always()' 27 | 28 | branding: 29 | icon: loader 30 | color: 'yellow' 31 | -------------------------------------------------------------------------------- /cleanup.js: -------------------------------------------------------------------------------- 1 | const { execFileSync } = require('child_process'); 2 | const { sshAgentCmd } = require('./paths.js'); 3 | 4 | try { 5 | // Kill the started SSH agent 6 | console.log('Stopping SSH agent'); 7 | execFileSync(sshAgentCmd, ['-k'], { stdio: 'inherit' }); 8 | } catch (error) { 9 | console.log(error.message); 10 | console.log('Error stopping the SSH agent, proceeding anyway'); 11 | } 12 | -------------------------------------------------------------------------------- /dist/cleanup.js: -------------------------------------------------------------------------------- 1 | module.exports = 2 | /******/ (function(modules, runtime) { // webpackBootstrap 3 | /******/ "use strict"; 4 | /******/ // The module cache 5 | /******/ var installedModules = {}; 6 | /******/ 7 | /******/ // The require function 8 | /******/ function __webpack_require__(moduleId) { 9 | /******/ 10 | /******/ // Check if module is in cache 11 | /******/ if(installedModules[moduleId]) { 12 | /******/ return installedModules[moduleId].exports; 13 | /******/ } 14 | /******/ // Create a new module (and put it into the cache) 15 | /******/ var module = installedModules[moduleId] = { 16 | /******/ i: moduleId, 17 | /******/ l: false, 18 | /******/ exports: {} 19 | /******/ }; 20 | /******/ 21 | /******/ // Execute the module function 22 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 23 | /******/ 24 | /******/ // Flag the module as loaded 25 | /******/ module.l = true; 26 | /******/ 27 | /******/ // Return the exports of the module 28 | /******/ return module.exports; 29 | /******/ } 30 | /******/ 31 | /******/ 32 | /******/ __webpack_require__.ab = __dirname + "/"; 33 | /******/ 34 | /******/ // the startup function 35 | /******/ function startup() { 36 | /******/ // Load entry module and return exports 37 | /******/ return __webpack_require__(175); 38 | /******/ }; 39 | /******/ 40 | /******/ // run startup 41 | /******/ return startup(); 42 | /******/ }) 43 | /************************************************************************/ 44 | /******/ ({ 45 | 46 | /***/ 16: 47 | /***/ (function(module) { 48 | 49 | module.exports = require("tls"); 50 | 51 | /***/ }), 52 | 53 | /***/ 22: 54 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 55 | 56 | "use strict"; 57 | 58 | 59 | Object.defineProperty(exports, "__esModule", { 60 | value: true 61 | }); 62 | exports.default = void 0; 63 | 64 | var _validate = _interopRequireDefault(__webpack_require__(78)); 65 | 66 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 67 | 68 | function parse(uuid) { 69 | if (!(0, _validate.default)(uuid)) { 70 | throw TypeError('Invalid UUID'); 71 | } 72 | 73 | let v; 74 | const arr = new Uint8Array(16); // Parse ########-....-....-....-............ 75 | 76 | arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; 77 | arr[1] = v >>> 16 & 0xff; 78 | arr[2] = v >>> 8 & 0xff; 79 | arr[3] = v & 0xff; // Parse ........-####-....-....-............ 80 | 81 | arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; 82 | arr[5] = v & 0xff; // Parse ........-....-####-....-............ 83 | 84 | arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; 85 | arr[7] = v & 0xff; // Parse ........-....-....-####-............ 86 | 87 | arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; 88 | arr[9] = v & 0xff; // Parse ........-....-....-....-############ 89 | // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) 90 | 91 | arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; 92 | arr[11] = v / 0x100000000 & 0xff; 93 | arr[12] = v >>> 24 & 0xff; 94 | arr[13] = v >>> 16 & 0xff; 95 | arr[14] = v >>> 8 & 0xff; 96 | arr[15] = v & 0xff; 97 | return arr; 98 | } 99 | 100 | var _default = parse; 101 | exports.default = _default; 102 | 103 | /***/ }), 104 | 105 | /***/ 62: 106 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 107 | 108 | "use strict"; 109 | 110 | 111 | Object.defineProperty(exports, "__esModule", { 112 | value: true 113 | }); 114 | Object.defineProperty(exports, "v1", { 115 | enumerable: true, 116 | get: function () { 117 | return _v.default; 118 | } 119 | }); 120 | Object.defineProperty(exports, "v3", { 121 | enumerable: true, 122 | get: function () { 123 | return _v2.default; 124 | } 125 | }); 126 | Object.defineProperty(exports, "v4", { 127 | enumerable: true, 128 | get: function () { 129 | return _v3.default; 130 | } 131 | }); 132 | Object.defineProperty(exports, "v5", { 133 | enumerable: true, 134 | get: function () { 135 | return _v4.default; 136 | } 137 | }); 138 | Object.defineProperty(exports, "NIL", { 139 | enumerable: true, 140 | get: function () { 141 | return _nil.default; 142 | } 143 | }); 144 | Object.defineProperty(exports, "version", { 145 | enumerable: true, 146 | get: function () { 147 | return _version.default; 148 | } 149 | }); 150 | Object.defineProperty(exports, "validate", { 151 | enumerable: true, 152 | get: function () { 153 | return _validate.default; 154 | } 155 | }); 156 | Object.defineProperty(exports, "stringify", { 157 | enumerable: true, 158 | get: function () { 159 | return _stringify.default; 160 | } 161 | }); 162 | Object.defineProperty(exports, "parse", { 163 | enumerable: true, 164 | get: function () { 165 | return _parse.default; 166 | } 167 | }); 168 | 169 | var _v = _interopRequireDefault(__webpack_require__(893)); 170 | 171 | var _v2 = _interopRequireDefault(__webpack_require__(209)); 172 | 173 | var _v3 = _interopRequireDefault(__webpack_require__(733)); 174 | 175 | var _v4 = _interopRequireDefault(__webpack_require__(384)); 176 | 177 | var _nil = _interopRequireDefault(__webpack_require__(327)); 178 | 179 | var _version = _interopRequireDefault(__webpack_require__(695)); 180 | 181 | var _validate = _interopRequireDefault(__webpack_require__(78)); 182 | 183 | var _stringify = _interopRequireDefault(__webpack_require__(411)); 184 | 185 | var _parse = _interopRequireDefault(__webpack_require__(22)); 186 | 187 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 188 | 189 | /***/ }), 190 | 191 | /***/ 78: 192 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 193 | 194 | "use strict"; 195 | 196 | 197 | Object.defineProperty(exports, "__esModule", { 198 | value: true 199 | }); 200 | exports.default = void 0; 201 | 202 | var _regex = _interopRequireDefault(__webpack_require__(456)); 203 | 204 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 205 | 206 | function validate(uuid) { 207 | return typeof uuid === 'string' && _regex.default.test(uuid); 208 | } 209 | 210 | var _default = validate; 211 | exports.default = _default; 212 | 213 | /***/ }), 214 | 215 | /***/ 82: 216 | /***/ (function(__unusedmodule, exports) { 217 | 218 | "use strict"; 219 | 220 | // We use any as a valid input type 221 | /* eslint-disable @typescript-eslint/no-explicit-any */ 222 | Object.defineProperty(exports, "__esModule", { value: true }); 223 | exports.toCommandProperties = exports.toCommandValue = void 0; 224 | /** 225 | * Sanitizes an input into a string so it can be passed into issueCommand safely 226 | * @param input input to sanitize into a string 227 | */ 228 | function toCommandValue(input) { 229 | if (input === null || input === undefined) { 230 | return ''; 231 | } 232 | else if (typeof input === 'string' || input instanceof String) { 233 | return input; 234 | } 235 | return JSON.stringify(input); 236 | } 237 | exports.toCommandValue = toCommandValue; 238 | /** 239 | * 240 | * @param annotationProperties 241 | * @returns The command properties to send with the actual annotation command 242 | * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646 243 | */ 244 | function toCommandProperties(annotationProperties) { 245 | if (!Object.keys(annotationProperties).length) { 246 | return {}; 247 | } 248 | return { 249 | title: annotationProperties.title, 250 | file: annotationProperties.file, 251 | line: annotationProperties.startLine, 252 | endLine: annotationProperties.endLine, 253 | col: annotationProperties.startColumn, 254 | endColumn: annotationProperties.endColumn 255 | }; 256 | } 257 | exports.toCommandProperties = toCommandProperties; 258 | //# sourceMappingURL=utils.js.map 259 | 260 | /***/ }), 261 | 262 | /***/ 87: 263 | /***/ (function(module) { 264 | 265 | module.exports = require("os"); 266 | 267 | /***/ }), 268 | 269 | /***/ 102: 270 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 271 | 272 | "use strict"; 273 | 274 | // For internal use, subject to change. 275 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 276 | if (k2 === undefined) k2 = k; 277 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 278 | }) : (function(o, m, k, k2) { 279 | if (k2 === undefined) k2 = k; 280 | o[k2] = m[k]; 281 | })); 282 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 283 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 284 | }) : function(o, v) { 285 | o["default"] = v; 286 | }); 287 | var __importStar = (this && this.__importStar) || function (mod) { 288 | if (mod && mod.__esModule) return mod; 289 | var result = {}; 290 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 291 | __setModuleDefault(result, mod); 292 | return result; 293 | }; 294 | Object.defineProperty(exports, "__esModule", { value: true }); 295 | exports.issueCommand = void 0; 296 | // We use any as a valid input type 297 | /* eslint-disable @typescript-eslint/no-explicit-any */ 298 | const fs = __importStar(__webpack_require__(747)); 299 | const os = __importStar(__webpack_require__(87)); 300 | const utils_1 = __webpack_require__(82); 301 | function issueCommand(command, message) { 302 | const filePath = process.env[`GITHUB_${command}`]; 303 | if (!filePath) { 304 | throw new Error(`Unable to find environment variable for file command ${command}`); 305 | } 306 | if (!fs.existsSync(filePath)) { 307 | throw new Error(`Missing file at path: ${filePath}`); 308 | } 309 | fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, { 310 | encoding: 'utf8' 311 | }); 312 | } 313 | exports.issueCommand = issueCommand; 314 | //# sourceMappingURL=file-command.js.map 315 | 316 | /***/ }), 317 | 318 | /***/ 129: 319 | /***/ (function(module) { 320 | 321 | module.exports = require("child_process"); 322 | 323 | /***/ }), 324 | 325 | /***/ 141: 326 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 327 | 328 | "use strict"; 329 | 330 | 331 | var net = __webpack_require__(631); 332 | var tls = __webpack_require__(16); 333 | var http = __webpack_require__(605); 334 | var https = __webpack_require__(211); 335 | var events = __webpack_require__(614); 336 | var assert = __webpack_require__(357); 337 | var util = __webpack_require__(669); 338 | 339 | 340 | exports.httpOverHttp = httpOverHttp; 341 | exports.httpsOverHttp = httpsOverHttp; 342 | exports.httpOverHttps = httpOverHttps; 343 | exports.httpsOverHttps = httpsOverHttps; 344 | 345 | 346 | function httpOverHttp(options) { 347 | var agent = new TunnelingAgent(options); 348 | agent.request = http.request; 349 | return agent; 350 | } 351 | 352 | function httpsOverHttp(options) { 353 | var agent = new TunnelingAgent(options); 354 | agent.request = http.request; 355 | agent.createSocket = createSecureSocket; 356 | agent.defaultPort = 443; 357 | return agent; 358 | } 359 | 360 | function httpOverHttps(options) { 361 | var agent = new TunnelingAgent(options); 362 | agent.request = https.request; 363 | return agent; 364 | } 365 | 366 | function httpsOverHttps(options) { 367 | var agent = new TunnelingAgent(options); 368 | agent.request = https.request; 369 | agent.createSocket = createSecureSocket; 370 | agent.defaultPort = 443; 371 | return agent; 372 | } 373 | 374 | 375 | function TunnelingAgent(options) { 376 | var self = this; 377 | self.options = options || {}; 378 | self.proxyOptions = self.options.proxy || {}; 379 | self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets; 380 | self.requests = []; 381 | self.sockets = []; 382 | 383 | self.on('free', function onFree(socket, host, port, localAddress) { 384 | var options = toOptions(host, port, localAddress); 385 | for (var i = 0, len = self.requests.length; i < len; ++i) { 386 | var pending = self.requests[i]; 387 | if (pending.host === options.host && pending.port === options.port) { 388 | // Detect the request to connect same origin server, 389 | // reuse the connection. 390 | self.requests.splice(i, 1); 391 | pending.request.onSocket(socket); 392 | return; 393 | } 394 | } 395 | socket.destroy(); 396 | self.removeSocket(socket); 397 | }); 398 | } 399 | util.inherits(TunnelingAgent, events.EventEmitter); 400 | 401 | TunnelingAgent.prototype.addRequest = function addRequest(req, host, port, localAddress) { 402 | var self = this; 403 | var options = mergeOptions({request: req}, self.options, toOptions(host, port, localAddress)); 404 | 405 | if (self.sockets.length >= this.maxSockets) { 406 | // We are over limit so we'll add it to the queue. 407 | self.requests.push(options); 408 | return; 409 | } 410 | 411 | // If we are under maxSockets create a new one. 412 | self.createSocket(options, function(socket) { 413 | socket.on('free', onFree); 414 | socket.on('close', onCloseOrRemove); 415 | socket.on('agentRemove', onCloseOrRemove); 416 | req.onSocket(socket); 417 | 418 | function onFree() { 419 | self.emit('free', socket, options); 420 | } 421 | 422 | function onCloseOrRemove(err) { 423 | self.removeSocket(socket); 424 | socket.removeListener('free', onFree); 425 | socket.removeListener('close', onCloseOrRemove); 426 | socket.removeListener('agentRemove', onCloseOrRemove); 427 | } 428 | }); 429 | }; 430 | 431 | TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { 432 | var self = this; 433 | var placeholder = {}; 434 | self.sockets.push(placeholder); 435 | 436 | var connectOptions = mergeOptions({}, self.proxyOptions, { 437 | method: 'CONNECT', 438 | path: options.host + ':' + options.port, 439 | agent: false, 440 | headers: { 441 | host: options.host + ':' + options.port 442 | } 443 | }); 444 | if (options.localAddress) { 445 | connectOptions.localAddress = options.localAddress; 446 | } 447 | if (connectOptions.proxyAuth) { 448 | connectOptions.headers = connectOptions.headers || {}; 449 | connectOptions.headers['Proxy-Authorization'] = 'Basic ' + 450 | new Buffer(connectOptions.proxyAuth).toString('base64'); 451 | } 452 | 453 | debug('making CONNECT request'); 454 | var connectReq = self.request(connectOptions); 455 | connectReq.useChunkedEncodingByDefault = false; // for v0.6 456 | connectReq.once('response', onResponse); // for v0.6 457 | connectReq.once('upgrade', onUpgrade); // for v0.6 458 | connectReq.once('connect', onConnect); // for v0.7 or later 459 | connectReq.once('error', onError); 460 | connectReq.end(); 461 | 462 | function onResponse(res) { 463 | // Very hacky. This is necessary to avoid http-parser leaks. 464 | res.upgrade = true; 465 | } 466 | 467 | function onUpgrade(res, socket, head) { 468 | // Hacky. 469 | process.nextTick(function() { 470 | onConnect(res, socket, head); 471 | }); 472 | } 473 | 474 | function onConnect(res, socket, head) { 475 | connectReq.removeAllListeners(); 476 | socket.removeAllListeners(); 477 | 478 | if (res.statusCode !== 200) { 479 | debug('tunneling socket could not be established, statusCode=%d', 480 | res.statusCode); 481 | socket.destroy(); 482 | var error = new Error('tunneling socket could not be established, ' + 483 | 'statusCode=' + res.statusCode); 484 | error.code = 'ECONNRESET'; 485 | options.request.emit('error', error); 486 | self.removeSocket(placeholder); 487 | return; 488 | } 489 | if (head.length > 0) { 490 | debug('got illegal response body from proxy'); 491 | socket.destroy(); 492 | var error = new Error('got illegal response body from proxy'); 493 | error.code = 'ECONNRESET'; 494 | options.request.emit('error', error); 495 | self.removeSocket(placeholder); 496 | return; 497 | } 498 | debug('tunneling connection has established'); 499 | self.sockets[self.sockets.indexOf(placeholder)] = socket; 500 | return cb(socket); 501 | } 502 | 503 | function onError(cause) { 504 | connectReq.removeAllListeners(); 505 | 506 | debug('tunneling socket could not be established, cause=%s\n', 507 | cause.message, cause.stack); 508 | var error = new Error('tunneling socket could not be established, ' + 509 | 'cause=' + cause.message); 510 | error.code = 'ECONNRESET'; 511 | options.request.emit('error', error); 512 | self.removeSocket(placeholder); 513 | } 514 | }; 515 | 516 | TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { 517 | var pos = this.sockets.indexOf(socket) 518 | if (pos === -1) { 519 | return; 520 | } 521 | this.sockets.splice(pos, 1); 522 | 523 | var pending = this.requests.shift(); 524 | if (pending) { 525 | // If we have pending requests and a socket gets closed a new one 526 | // needs to be created to take over in the pool for the one that closed. 527 | this.createSocket(pending, function(socket) { 528 | pending.request.onSocket(socket); 529 | }); 530 | } 531 | }; 532 | 533 | function createSecureSocket(options, cb) { 534 | var self = this; 535 | TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { 536 | var hostHeader = options.request.getHeader('host'); 537 | var tlsOptions = mergeOptions({}, self.options, { 538 | socket: socket, 539 | servername: hostHeader ? hostHeader.replace(/:.*$/, '') : options.host 540 | }); 541 | 542 | // 0 is dummy port for v0.6 543 | var secureSocket = tls.connect(0, tlsOptions); 544 | self.sockets[self.sockets.indexOf(socket)] = secureSocket; 545 | cb(secureSocket); 546 | }); 547 | } 548 | 549 | 550 | function toOptions(host, port, localAddress) { 551 | if (typeof host === 'string') { // since v0.10 552 | return { 553 | host: host, 554 | port: port, 555 | localAddress: localAddress 556 | }; 557 | } 558 | return host; // for v0.11 or later 559 | } 560 | 561 | function mergeOptions(target) { 562 | for (var i = 1, len = arguments.length; i < len; ++i) { 563 | var overrides = arguments[i]; 564 | if (typeof overrides === 'object') { 565 | var keys = Object.keys(overrides); 566 | for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { 567 | var k = keys[j]; 568 | if (overrides[k] !== undefined) { 569 | target[k] = overrides[k]; 570 | } 571 | } 572 | } 573 | } 574 | return target; 575 | } 576 | 577 | 578 | var debug; 579 | if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { 580 | debug = function() { 581 | var args = Array.prototype.slice.call(arguments); 582 | if (typeof args[0] === 'string') { 583 | args[0] = 'TUNNEL: ' + args[0]; 584 | } else { 585 | args.unshift('TUNNEL:'); 586 | } 587 | console.error.apply(console, args); 588 | } 589 | } else { 590 | debug = function() {}; 591 | } 592 | exports.debug = debug; // for test 593 | 594 | 595 | /***/ }), 596 | 597 | /***/ 175: 598 | /***/ (function(__unusedmodule, __unusedexports, __webpack_require__) { 599 | 600 | const { execFileSync } = __webpack_require__(129); 601 | const { sshAgentCmd } = __webpack_require__(972); 602 | 603 | try { 604 | // Kill the started SSH agent 605 | console.log('Stopping SSH agent'); 606 | execFileSync(sshAgentCmd, ['-k'], { stdio: 'inherit' }); 607 | } catch (error) { 608 | console.log(error.message); 609 | console.log('Error stopping the SSH agent, proceeding anyway'); 610 | } 611 | 612 | 613 | /***/ }), 614 | 615 | /***/ 177: 616 | /***/ (function(__unusedmodule, exports) { 617 | 618 | "use strict"; 619 | 620 | Object.defineProperty(exports, "__esModule", { value: true }); 621 | exports.checkBypass = exports.getProxyUrl = void 0; 622 | function getProxyUrl(reqUrl) { 623 | const usingSsl = reqUrl.protocol === 'https:'; 624 | if (checkBypass(reqUrl)) { 625 | return undefined; 626 | } 627 | const proxyVar = (() => { 628 | if (usingSsl) { 629 | return process.env['https_proxy'] || process.env['HTTPS_PROXY']; 630 | } 631 | else { 632 | return process.env['http_proxy'] || process.env['HTTP_PROXY']; 633 | } 634 | })(); 635 | if (proxyVar) { 636 | return new URL(proxyVar); 637 | } 638 | else { 639 | return undefined; 640 | } 641 | } 642 | exports.getProxyUrl = getProxyUrl; 643 | function checkBypass(reqUrl) { 644 | if (!reqUrl.hostname) { 645 | return false; 646 | } 647 | const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || ''; 648 | if (!noProxy) { 649 | return false; 650 | } 651 | // Determine the request port 652 | let reqPort; 653 | if (reqUrl.port) { 654 | reqPort = Number(reqUrl.port); 655 | } 656 | else if (reqUrl.protocol === 'http:') { 657 | reqPort = 80; 658 | } 659 | else if (reqUrl.protocol === 'https:') { 660 | reqPort = 443; 661 | } 662 | // Format the request hostname and hostname with port 663 | const upperReqHosts = [reqUrl.hostname.toUpperCase()]; 664 | if (typeof reqPort === 'number') { 665 | upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`); 666 | } 667 | // Compare request host against noproxy 668 | for (const upperNoProxyItem of noProxy 669 | .split(',') 670 | .map(x => x.trim().toUpperCase()) 671 | .filter(x => x)) { 672 | if (upperReqHosts.some(x => x === upperNoProxyItem)) { 673 | return true; 674 | } 675 | } 676 | return false; 677 | } 678 | exports.checkBypass = checkBypass; 679 | //# sourceMappingURL=proxy.js.map 680 | 681 | /***/ }), 682 | 683 | /***/ 209: 684 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 685 | 686 | "use strict"; 687 | 688 | 689 | Object.defineProperty(exports, "__esModule", { 690 | value: true 691 | }); 692 | exports.default = void 0; 693 | 694 | var _v = _interopRequireDefault(__webpack_require__(212)); 695 | 696 | var _md = _interopRequireDefault(__webpack_require__(803)); 697 | 698 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 699 | 700 | const v3 = (0, _v.default)('v3', 0x30, _md.default); 701 | var _default = v3; 702 | exports.default = _default; 703 | 704 | /***/ }), 705 | 706 | /***/ 211: 707 | /***/ (function(module) { 708 | 709 | module.exports = require("https"); 710 | 711 | /***/ }), 712 | 713 | /***/ 212: 714 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 715 | 716 | "use strict"; 717 | 718 | 719 | Object.defineProperty(exports, "__esModule", { 720 | value: true 721 | }); 722 | exports.default = _default; 723 | exports.URL = exports.DNS = void 0; 724 | 725 | var _stringify = _interopRequireDefault(__webpack_require__(411)); 726 | 727 | var _parse = _interopRequireDefault(__webpack_require__(22)); 728 | 729 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 730 | 731 | function stringToBytes(str) { 732 | str = unescape(encodeURIComponent(str)); // UTF8 escape 733 | 734 | const bytes = []; 735 | 736 | for (let i = 0; i < str.length; ++i) { 737 | bytes.push(str.charCodeAt(i)); 738 | } 739 | 740 | return bytes; 741 | } 742 | 743 | const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; 744 | exports.DNS = DNS; 745 | const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; 746 | exports.URL = URL; 747 | 748 | function _default(name, version, hashfunc) { 749 | function generateUUID(value, namespace, buf, offset) { 750 | if (typeof value === 'string') { 751 | value = stringToBytes(value); 752 | } 753 | 754 | if (typeof namespace === 'string') { 755 | namespace = (0, _parse.default)(namespace); 756 | } 757 | 758 | if (namespace.length !== 16) { 759 | throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); 760 | } // Compute hash of namespace and value, Per 4.3 761 | // Future: Use spread syntax when supported on all platforms, e.g. `bytes = 762 | // hashfunc([...namespace, ... value])` 763 | 764 | 765 | let bytes = new Uint8Array(16 + value.length); 766 | bytes.set(namespace); 767 | bytes.set(value, namespace.length); 768 | bytes = hashfunc(bytes); 769 | bytes[6] = bytes[6] & 0x0f | version; 770 | bytes[8] = bytes[8] & 0x3f | 0x80; 771 | 772 | if (buf) { 773 | offset = offset || 0; 774 | 775 | for (let i = 0; i < 16; ++i) { 776 | buf[offset + i] = bytes[i]; 777 | } 778 | 779 | return buf; 780 | } 781 | 782 | return (0, _stringify.default)(bytes); 783 | } // Function#name is not settable on some platforms (#270) 784 | 785 | 786 | try { 787 | generateUUID.name = name; // eslint-disable-next-line no-empty 788 | } catch (err) {} // For CommonJS default export support 789 | 790 | 791 | generateUUID.DNS = DNS; 792 | generateUUID.URL = URL; 793 | return generateUUID; 794 | } 795 | 796 | /***/ }), 797 | 798 | /***/ 327: 799 | /***/ (function(__unusedmodule, exports) { 800 | 801 | "use strict"; 802 | 803 | 804 | Object.defineProperty(exports, "__esModule", { 805 | value: true 806 | }); 807 | exports.default = void 0; 808 | var _default = '00000000-0000-0000-0000-000000000000'; 809 | exports.default = _default; 810 | 811 | /***/ }), 812 | 813 | /***/ 357: 814 | /***/ (function(module) { 815 | 816 | module.exports = require("assert"); 817 | 818 | /***/ }), 819 | 820 | /***/ 384: 821 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 822 | 823 | "use strict"; 824 | 825 | 826 | Object.defineProperty(exports, "__esModule", { 827 | value: true 828 | }); 829 | exports.default = void 0; 830 | 831 | var _v = _interopRequireDefault(__webpack_require__(212)); 832 | 833 | var _sha = _interopRequireDefault(__webpack_require__(498)); 834 | 835 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 836 | 837 | const v5 = (0, _v.default)('v5', 0x50, _sha.default); 838 | var _default = v5; 839 | exports.default = _default; 840 | 841 | /***/ }), 842 | 843 | /***/ 411: 844 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 845 | 846 | "use strict"; 847 | 848 | 849 | Object.defineProperty(exports, "__esModule", { 850 | value: true 851 | }); 852 | exports.default = void 0; 853 | 854 | var _validate = _interopRequireDefault(__webpack_require__(78)); 855 | 856 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 857 | 858 | /** 859 | * Convert array of 16 byte values to UUID string format of the form: 860 | * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 861 | */ 862 | const byteToHex = []; 863 | 864 | for (let i = 0; i < 256; ++i) { 865 | byteToHex.push((i + 0x100).toString(16).substr(1)); 866 | } 867 | 868 | function stringify(arr, offset = 0) { 869 | // Note: Be careful editing this code! It's been tuned for performance 870 | // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 871 | const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one 872 | // of the following: 873 | // - One or more input array values don't map to a hex octet (leading to 874 | // "undefined" in the uuid) 875 | // - Invalid input values for the RFC `version` or `variant` fields 876 | 877 | if (!(0, _validate.default)(uuid)) { 878 | throw TypeError('Stringified UUID is invalid'); 879 | } 880 | 881 | return uuid; 882 | } 883 | 884 | var _default = stringify; 885 | exports.default = _default; 886 | 887 | /***/ }), 888 | 889 | /***/ 413: 890 | /***/ (function(module, __unusedexports, __webpack_require__) { 891 | 892 | module.exports = __webpack_require__(141); 893 | 894 | 895 | /***/ }), 896 | 897 | /***/ 417: 898 | /***/ (function(module) { 899 | 900 | module.exports = require("crypto"); 901 | 902 | /***/ }), 903 | 904 | /***/ 425: 905 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 906 | 907 | "use strict"; 908 | 909 | /* eslint-disable @typescript-eslint/no-explicit-any */ 910 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 911 | if (k2 === undefined) k2 = k; 912 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 913 | }) : (function(o, m, k, k2) { 914 | if (k2 === undefined) k2 = k; 915 | o[k2] = m[k]; 916 | })); 917 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 918 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 919 | }) : function(o, v) { 920 | o["default"] = v; 921 | }); 922 | var __importStar = (this && this.__importStar) || function (mod) { 923 | if (mod && mod.__esModule) return mod; 924 | var result = {}; 925 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 926 | __setModuleDefault(result, mod); 927 | return result; 928 | }; 929 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 930 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 931 | return new (P || (P = Promise))(function (resolve, reject) { 932 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 933 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 934 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 935 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 936 | }); 937 | }; 938 | Object.defineProperty(exports, "__esModule", { value: true }); 939 | exports.HttpClient = exports.isHttps = exports.HttpClientResponse = exports.HttpClientError = exports.getProxyUrl = exports.MediaTypes = exports.Headers = exports.HttpCodes = void 0; 940 | const http = __importStar(__webpack_require__(605)); 941 | const https = __importStar(__webpack_require__(211)); 942 | const pm = __importStar(__webpack_require__(177)); 943 | const tunnel = __importStar(__webpack_require__(413)); 944 | var HttpCodes; 945 | (function (HttpCodes) { 946 | HttpCodes[HttpCodes["OK"] = 200] = "OK"; 947 | HttpCodes[HttpCodes["MultipleChoices"] = 300] = "MultipleChoices"; 948 | HttpCodes[HttpCodes["MovedPermanently"] = 301] = "MovedPermanently"; 949 | HttpCodes[HttpCodes["ResourceMoved"] = 302] = "ResourceMoved"; 950 | HttpCodes[HttpCodes["SeeOther"] = 303] = "SeeOther"; 951 | HttpCodes[HttpCodes["NotModified"] = 304] = "NotModified"; 952 | HttpCodes[HttpCodes["UseProxy"] = 305] = "UseProxy"; 953 | HttpCodes[HttpCodes["SwitchProxy"] = 306] = "SwitchProxy"; 954 | HttpCodes[HttpCodes["TemporaryRedirect"] = 307] = "TemporaryRedirect"; 955 | HttpCodes[HttpCodes["PermanentRedirect"] = 308] = "PermanentRedirect"; 956 | HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest"; 957 | HttpCodes[HttpCodes["Unauthorized"] = 401] = "Unauthorized"; 958 | HttpCodes[HttpCodes["PaymentRequired"] = 402] = "PaymentRequired"; 959 | HttpCodes[HttpCodes["Forbidden"] = 403] = "Forbidden"; 960 | HttpCodes[HttpCodes["NotFound"] = 404] = "NotFound"; 961 | HttpCodes[HttpCodes["MethodNotAllowed"] = 405] = "MethodNotAllowed"; 962 | HttpCodes[HttpCodes["NotAcceptable"] = 406] = "NotAcceptable"; 963 | HttpCodes[HttpCodes["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; 964 | HttpCodes[HttpCodes["RequestTimeout"] = 408] = "RequestTimeout"; 965 | HttpCodes[HttpCodes["Conflict"] = 409] = "Conflict"; 966 | HttpCodes[HttpCodes["Gone"] = 410] = "Gone"; 967 | HttpCodes[HttpCodes["TooManyRequests"] = 429] = "TooManyRequests"; 968 | HttpCodes[HttpCodes["InternalServerError"] = 500] = "InternalServerError"; 969 | HttpCodes[HttpCodes["NotImplemented"] = 501] = "NotImplemented"; 970 | HttpCodes[HttpCodes["BadGateway"] = 502] = "BadGateway"; 971 | HttpCodes[HttpCodes["ServiceUnavailable"] = 503] = "ServiceUnavailable"; 972 | HttpCodes[HttpCodes["GatewayTimeout"] = 504] = "GatewayTimeout"; 973 | })(HttpCodes = exports.HttpCodes || (exports.HttpCodes = {})); 974 | var Headers; 975 | (function (Headers) { 976 | Headers["Accept"] = "accept"; 977 | Headers["ContentType"] = "content-type"; 978 | })(Headers = exports.Headers || (exports.Headers = {})); 979 | var MediaTypes; 980 | (function (MediaTypes) { 981 | MediaTypes["ApplicationJson"] = "application/json"; 982 | })(MediaTypes = exports.MediaTypes || (exports.MediaTypes = {})); 983 | /** 984 | * Returns the proxy URL, depending upon the supplied url and proxy environment variables. 985 | * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 986 | */ 987 | function getProxyUrl(serverUrl) { 988 | const proxyUrl = pm.getProxyUrl(new URL(serverUrl)); 989 | return proxyUrl ? proxyUrl.href : ''; 990 | } 991 | exports.getProxyUrl = getProxyUrl; 992 | const HttpRedirectCodes = [ 993 | HttpCodes.MovedPermanently, 994 | HttpCodes.ResourceMoved, 995 | HttpCodes.SeeOther, 996 | HttpCodes.TemporaryRedirect, 997 | HttpCodes.PermanentRedirect 998 | ]; 999 | const HttpResponseRetryCodes = [ 1000 | HttpCodes.BadGateway, 1001 | HttpCodes.ServiceUnavailable, 1002 | HttpCodes.GatewayTimeout 1003 | ]; 1004 | const RetryableHttpVerbs = ['OPTIONS', 'GET', 'DELETE', 'HEAD']; 1005 | const ExponentialBackoffCeiling = 10; 1006 | const ExponentialBackoffTimeSlice = 5; 1007 | class HttpClientError extends Error { 1008 | constructor(message, statusCode) { 1009 | super(message); 1010 | this.name = 'HttpClientError'; 1011 | this.statusCode = statusCode; 1012 | Object.setPrototypeOf(this, HttpClientError.prototype); 1013 | } 1014 | } 1015 | exports.HttpClientError = HttpClientError; 1016 | class HttpClientResponse { 1017 | constructor(message) { 1018 | this.message = message; 1019 | } 1020 | readBody() { 1021 | return __awaiter(this, void 0, void 0, function* () { 1022 | return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { 1023 | let output = Buffer.alloc(0); 1024 | this.message.on('data', (chunk) => { 1025 | output = Buffer.concat([output, chunk]); 1026 | }); 1027 | this.message.on('end', () => { 1028 | resolve(output.toString()); 1029 | }); 1030 | })); 1031 | }); 1032 | } 1033 | } 1034 | exports.HttpClientResponse = HttpClientResponse; 1035 | function isHttps(requestUrl) { 1036 | const parsedUrl = new URL(requestUrl); 1037 | return parsedUrl.protocol === 'https:'; 1038 | } 1039 | exports.isHttps = isHttps; 1040 | class HttpClient { 1041 | constructor(userAgent, handlers, requestOptions) { 1042 | this._ignoreSslError = false; 1043 | this._allowRedirects = true; 1044 | this._allowRedirectDowngrade = false; 1045 | this._maxRedirects = 50; 1046 | this._allowRetries = false; 1047 | this._maxRetries = 1; 1048 | this._keepAlive = false; 1049 | this._disposed = false; 1050 | this.userAgent = userAgent; 1051 | this.handlers = handlers || []; 1052 | this.requestOptions = requestOptions; 1053 | if (requestOptions) { 1054 | if (requestOptions.ignoreSslError != null) { 1055 | this._ignoreSslError = requestOptions.ignoreSslError; 1056 | } 1057 | this._socketTimeout = requestOptions.socketTimeout; 1058 | if (requestOptions.allowRedirects != null) { 1059 | this._allowRedirects = requestOptions.allowRedirects; 1060 | } 1061 | if (requestOptions.allowRedirectDowngrade != null) { 1062 | this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade; 1063 | } 1064 | if (requestOptions.maxRedirects != null) { 1065 | this._maxRedirects = Math.max(requestOptions.maxRedirects, 0); 1066 | } 1067 | if (requestOptions.keepAlive != null) { 1068 | this._keepAlive = requestOptions.keepAlive; 1069 | } 1070 | if (requestOptions.allowRetries != null) { 1071 | this._allowRetries = requestOptions.allowRetries; 1072 | } 1073 | if (requestOptions.maxRetries != null) { 1074 | this._maxRetries = requestOptions.maxRetries; 1075 | } 1076 | } 1077 | } 1078 | options(requestUrl, additionalHeaders) { 1079 | return __awaiter(this, void 0, void 0, function* () { 1080 | return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}); 1081 | }); 1082 | } 1083 | get(requestUrl, additionalHeaders) { 1084 | return __awaiter(this, void 0, void 0, function* () { 1085 | return this.request('GET', requestUrl, null, additionalHeaders || {}); 1086 | }); 1087 | } 1088 | del(requestUrl, additionalHeaders) { 1089 | return __awaiter(this, void 0, void 0, function* () { 1090 | return this.request('DELETE', requestUrl, null, additionalHeaders || {}); 1091 | }); 1092 | } 1093 | post(requestUrl, data, additionalHeaders) { 1094 | return __awaiter(this, void 0, void 0, function* () { 1095 | return this.request('POST', requestUrl, data, additionalHeaders || {}); 1096 | }); 1097 | } 1098 | patch(requestUrl, data, additionalHeaders) { 1099 | return __awaiter(this, void 0, void 0, function* () { 1100 | return this.request('PATCH', requestUrl, data, additionalHeaders || {}); 1101 | }); 1102 | } 1103 | put(requestUrl, data, additionalHeaders) { 1104 | return __awaiter(this, void 0, void 0, function* () { 1105 | return this.request('PUT', requestUrl, data, additionalHeaders || {}); 1106 | }); 1107 | } 1108 | head(requestUrl, additionalHeaders) { 1109 | return __awaiter(this, void 0, void 0, function* () { 1110 | return this.request('HEAD', requestUrl, null, additionalHeaders || {}); 1111 | }); 1112 | } 1113 | sendStream(verb, requestUrl, stream, additionalHeaders) { 1114 | return __awaiter(this, void 0, void 0, function* () { 1115 | return this.request(verb, requestUrl, stream, additionalHeaders); 1116 | }); 1117 | } 1118 | /** 1119 | * Gets a typed object from an endpoint 1120 | * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise 1121 | */ 1122 | getJson(requestUrl, additionalHeaders = {}) { 1123 | return __awaiter(this, void 0, void 0, function* () { 1124 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 1125 | const res = yield this.get(requestUrl, additionalHeaders); 1126 | return this._processResponse(res, this.requestOptions); 1127 | }); 1128 | } 1129 | postJson(requestUrl, obj, additionalHeaders = {}) { 1130 | return __awaiter(this, void 0, void 0, function* () { 1131 | const data = JSON.stringify(obj, null, 2); 1132 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 1133 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 1134 | const res = yield this.post(requestUrl, data, additionalHeaders); 1135 | return this._processResponse(res, this.requestOptions); 1136 | }); 1137 | } 1138 | putJson(requestUrl, obj, additionalHeaders = {}) { 1139 | return __awaiter(this, void 0, void 0, function* () { 1140 | const data = JSON.stringify(obj, null, 2); 1141 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 1142 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 1143 | const res = yield this.put(requestUrl, data, additionalHeaders); 1144 | return this._processResponse(res, this.requestOptions); 1145 | }); 1146 | } 1147 | patchJson(requestUrl, obj, additionalHeaders = {}) { 1148 | return __awaiter(this, void 0, void 0, function* () { 1149 | const data = JSON.stringify(obj, null, 2); 1150 | additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.Accept, MediaTypes.ApplicationJson); 1151 | additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader(additionalHeaders, Headers.ContentType, MediaTypes.ApplicationJson); 1152 | const res = yield this.patch(requestUrl, data, additionalHeaders); 1153 | return this._processResponse(res, this.requestOptions); 1154 | }); 1155 | } 1156 | /** 1157 | * Makes a raw http request. 1158 | * All other methods such as get, post, patch, and request ultimately call this. 1159 | * Prefer get, del, post and patch 1160 | */ 1161 | request(verb, requestUrl, data, headers) { 1162 | return __awaiter(this, void 0, void 0, function* () { 1163 | if (this._disposed) { 1164 | throw new Error('Client has already been disposed.'); 1165 | } 1166 | const parsedUrl = new URL(requestUrl); 1167 | let info = this._prepareRequest(verb, parsedUrl, headers); 1168 | // Only perform retries on reads since writes may not be idempotent. 1169 | const maxTries = this._allowRetries && RetryableHttpVerbs.includes(verb) 1170 | ? this._maxRetries + 1 1171 | : 1; 1172 | let numTries = 0; 1173 | let response; 1174 | do { 1175 | response = yield this.requestRaw(info, data); 1176 | // Check if it's an authentication challenge 1177 | if (response && 1178 | response.message && 1179 | response.message.statusCode === HttpCodes.Unauthorized) { 1180 | let authenticationHandler; 1181 | for (const handler of this.handlers) { 1182 | if (handler.canHandleAuthentication(response)) { 1183 | authenticationHandler = handler; 1184 | break; 1185 | } 1186 | } 1187 | if (authenticationHandler) { 1188 | return authenticationHandler.handleAuthentication(this, info, data); 1189 | } 1190 | else { 1191 | // We have received an unauthorized response but have no handlers to handle it. 1192 | // Let the response return to the caller. 1193 | return response; 1194 | } 1195 | } 1196 | let redirectsRemaining = this._maxRedirects; 1197 | while (response.message.statusCode && 1198 | HttpRedirectCodes.includes(response.message.statusCode) && 1199 | this._allowRedirects && 1200 | redirectsRemaining > 0) { 1201 | const redirectUrl = response.message.headers['location']; 1202 | if (!redirectUrl) { 1203 | // if there's no location to redirect to, we won't 1204 | break; 1205 | } 1206 | const parsedRedirectUrl = new URL(redirectUrl); 1207 | if (parsedUrl.protocol === 'https:' && 1208 | parsedUrl.protocol !== parsedRedirectUrl.protocol && 1209 | !this._allowRedirectDowngrade) { 1210 | throw new Error('Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.'); 1211 | } 1212 | // we need to finish reading the response before reassigning response 1213 | // which will leak the open socket. 1214 | yield response.readBody(); 1215 | // strip authorization header if redirected to a different hostname 1216 | if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { 1217 | for (const header in headers) { 1218 | // header names are case insensitive 1219 | if (header.toLowerCase() === 'authorization') { 1220 | delete headers[header]; 1221 | } 1222 | } 1223 | } 1224 | // let's make the request with the new redirectUrl 1225 | info = this._prepareRequest(verb, parsedRedirectUrl, headers); 1226 | response = yield this.requestRaw(info, data); 1227 | redirectsRemaining--; 1228 | } 1229 | if (!response.message.statusCode || 1230 | !HttpResponseRetryCodes.includes(response.message.statusCode)) { 1231 | // If not a retry code, return immediately instead of retrying 1232 | return response; 1233 | } 1234 | numTries += 1; 1235 | if (numTries < maxTries) { 1236 | yield response.readBody(); 1237 | yield this._performExponentialBackoff(numTries); 1238 | } 1239 | } while (numTries < maxTries); 1240 | return response; 1241 | }); 1242 | } 1243 | /** 1244 | * Needs to be called if keepAlive is set to true in request options. 1245 | */ 1246 | dispose() { 1247 | if (this._agent) { 1248 | this._agent.destroy(); 1249 | } 1250 | this._disposed = true; 1251 | } 1252 | /** 1253 | * Raw request. 1254 | * @param info 1255 | * @param data 1256 | */ 1257 | requestRaw(info, data) { 1258 | return __awaiter(this, void 0, void 0, function* () { 1259 | return new Promise((resolve, reject) => { 1260 | function callbackForResult(err, res) { 1261 | if (err) { 1262 | reject(err); 1263 | } 1264 | else if (!res) { 1265 | // If `err` is not passed, then `res` must be passed. 1266 | reject(new Error('Unknown error')); 1267 | } 1268 | else { 1269 | resolve(res); 1270 | } 1271 | } 1272 | this.requestRawWithCallback(info, data, callbackForResult); 1273 | }); 1274 | }); 1275 | } 1276 | /** 1277 | * Raw request with callback. 1278 | * @param info 1279 | * @param data 1280 | * @param onResult 1281 | */ 1282 | requestRawWithCallback(info, data, onResult) { 1283 | if (typeof data === 'string') { 1284 | if (!info.options.headers) { 1285 | info.options.headers = {}; 1286 | } 1287 | info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); 1288 | } 1289 | let callbackCalled = false; 1290 | function handleResult(err, res) { 1291 | if (!callbackCalled) { 1292 | callbackCalled = true; 1293 | onResult(err, res); 1294 | } 1295 | } 1296 | const req = info.httpModule.request(info.options, (msg) => { 1297 | const res = new HttpClientResponse(msg); 1298 | handleResult(undefined, res); 1299 | }); 1300 | let socket; 1301 | req.on('socket', sock => { 1302 | socket = sock; 1303 | }); 1304 | // If we ever get disconnected, we want the socket to timeout eventually 1305 | req.setTimeout(this._socketTimeout || 3 * 60000, () => { 1306 | if (socket) { 1307 | socket.end(); 1308 | } 1309 | handleResult(new Error(`Request timeout: ${info.options.path}`)); 1310 | }); 1311 | req.on('error', function (err) { 1312 | // err has statusCode property 1313 | // res should have headers 1314 | handleResult(err); 1315 | }); 1316 | if (data && typeof data === 'string') { 1317 | req.write(data, 'utf8'); 1318 | } 1319 | if (data && typeof data !== 'string') { 1320 | data.on('close', function () { 1321 | req.end(); 1322 | }); 1323 | data.pipe(req); 1324 | } 1325 | else { 1326 | req.end(); 1327 | } 1328 | } 1329 | /** 1330 | * Gets an http agent. This function is useful when you need an http agent that handles 1331 | * routing through a proxy server - depending upon the url and proxy environment variables. 1332 | * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com 1333 | */ 1334 | getAgent(serverUrl) { 1335 | const parsedUrl = new URL(serverUrl); 1336 | return this._getAgent(parsedUrl); 1337 | } 1338 | _prepareRequest(method, requestUrl, headers) { 1339 | const info = {}; 1340 | info.parsedUrl = requestUrl; 1341 | const usingSsl = info.parsedUrl.protocol === 'https:'; 1342 | info.httpModule = usingSsl ? https : http; 1343 | const defaultPort = usingSsl ? 443 : 80; 1344 | info.options = {}; 1345 | info.options.host = info.parsedUrl.hostname; 1346 | info.options.port = info.parsedUrl.port 1347 | ? parseInt(info.parsedUrl.port) 1348 | : defaultPort; 1349 | info.options.path = 1350 | (info.parsedUrl.pathname || '') + (info.parsedUrl.search || ''); 1351 | info.options.method = method; 1352 | info.options.headers = this._mergeHeaders(headers); 1353 | if (this.userAgent != null) { 1354 | info.options.headers['user-agent'] = this.userAgent; 1355 | } 1356 | info.options.agent = this._getAgent(info.parsedUrl); 1357 | // gives handlers an opportunity to participate 1358 | if (this.handlers) { 1359 | for (const handler of this.handlers) { 1360 | handler.prepareRequest(info.options); 1361 | } 1362 | } 1363 | return info; 1364 | } 1365 | _mergeHeaders(headers) { 1366 | if (this.requestOptions && this.requestOptions.headers) { 1367 | return Object.assign({}, lowercaseKeys(this.requestOptions.headers), lowercaseKeys(headers || {})); 1368 | } 1369 | return lowercaseKeys(headers || {}); 1370 | } 1371 | _getExistingOrDefaultHeader(additionalHeaders, header, _default) { 1372 | let clientHeader; 1373 | if (this.requestOptions && this.requestOptions.headers) { 1374 | clientHeader = lowercaseKeys(this.requestOptions.headers)[header]; 1375 | } 1376 | return additionalHeaders[header] || clientHeader || _default; 1377 | } 1378 | _getAgent(parsedUrl) { 1379 | let agent; 1380 | const proxyUrl = pm.getProxyUrl(parsedUrl); 1381 | const useProxy = proxyUrl && proxyUrl.hostname; 1382 | if (this._keepAlive && useProxy) { 1383 | agent = this._proxyAgent; 1384 | } 1385 | if (this._keepAlive && !useProxy) { 1386 | agent = this._agent; 1387 | } 1388 | // if agent is already assigned use that agent. 1389 | if (agent) { 1390 | return agent; 1391 | } 1392 | const usingSsl = parsedUrl.protocol === 'https:'; 1393 | let maxSockets = 100; 1394 | if (this.requestOptions) { 1395 | maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets; 1396 | } 1397 | // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. 1398 | if (proxyUrl && proxyUrl.hostname) { 1399 | const agentOptions = { 1400 | maxSockets, 1401 | keepAlive: this._keepAlive, 1402 | proxy: Object.assign(Object.assign({}, ((proxyUrl.username || proxyUrl.password) && { 1403 | proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` 1404 | })), { host: proxyUrl.hostname, port: proxyUrl.port }) 1405 | }; 1406 | let tunnelAgent; 1407 | const overHttps = proxyUrl.protocol === 'https:'; 1408 | if (usingSsl) { 1409 | tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp; 1410 | } 1411 | else { 1412 | tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp; 1413 | } 1414 | agent = tunnelAgent(agentOptions); 1415 | this._proxyAgent = agent; 1416 | } 1417 | // if reusing agent across request and tunneling agent isn't assigned create a new agent 1418 | if (this._keepAlive && !agent) { 1419 | const options = { keepAlive: this._keepAlive, maxSockets }; 1420 | agent = usingSsl ? new https.Agent(options) : new http.Agent(options); 1421 | this._agent = agent; 1422 | } 1423 | // if not using private agent and tunnel agent isn't setup then use global agent 1424 | if (!agent) { 1425 | agent = usingSsl ? https.globalAgent : http.globalAgent; 1426 | } 1427 | if (usingSsl && this._ignoreSslError) { 1428 | // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process 1429 | // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options 1430 | // we have to cast it to any and change it directly 1431 | agent.options = Object.assign(agent.options || {}, { 1432 | rejectUnauthorized: false 1433 | }); 1434 | } 1435 | return agent; 1436 | } 1437 | _performExponentialBackoff(retryNumber) { 1438 | return __awaiter(this, void 0, void 0, function* () { 1439 | retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber); 1440 | const ms = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber); 1441 | return new Promise(resolve => setTimeout(() => resolve(), ms)); 1442 | }); 1443 | } 1444 | _processResponse(res, options) { 1445 | return __awaiter(this, void 0, void 0, function* () { 1446 | return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { 1447 | const statusCode = res.message.statusCode || 0; 1448 | const response = { 1449 | statusCode, 1450 | result: null, 1451 | headers: {} 1452 | }; 1453 | // not found leads to null obj returned 1454 | if (statusCode === HttpCodes.NotFound) { 1455 | resolve(response); 1456 | } 1457 | // get the result from the body 1458 | function dateTimeDeserializer(key, value) { 1459 | if (typeof value === 'string') { 1460 | const a = new Date(value); 1461 | if (!isNaN(a.valueOf())) { 1462 | return a; 1463 | } 1464 | } 1465 | return value; 1466 | } 1467 | let obj; 1468 | let contents; 1469 | try { 1470 | contents = yield res.readBody(); 1471 | if (contents && contents.length > 0) { 1472 | if (options && options.deserializeDates) { 1473 | obj = JSON.parse(contents, dateTimeDeserializer); 1474 | } 1475 | else { 1476 | obj = JSON.parse(contents); 1477 | } 1478 | response.result = obj; 1479 | } 1480 | response.headers = res.message.headers; 1481 | } 1482 | catch (err) { 1483 | // Invalid resource (contents not json); leaving result obj null 1484 | } 1485 | // note that 3xx redirects are handled by the http layer. 1486 | if (statusCode > 299) { 1487 | let msg; 1488 | // if exception/error in body, attempt to get better error 1489 | if (obj && obj.message) { 1490 | msg = obj.message; 1491 | } 1492 | else if (contents && contents.length > 0) { 1493 | // it may be the case that the exception is in the body message as string 1494 | msg = contents; 1495 | } 1496 | else { 1497 | msg = `Failed request: (${statusCode})`; 1498 | } 1499 | const err = new HttpClientError(msg, statusCode); 1500 | err.result = response.result; 1501 | reject(err); 1502 | } 1503 | else { 1504 | resolve(response); 1505 | } 1506 | })); 1507 | }); 1508 | } 1509 | } 1510 | exports.HttpClient = HttpClient; 1511 | const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCase()] = obj[k]), c), {}); 1512 | //# sourceMappingURL=index.js.map 1513 | 1514 | /***/ }), 1515 | 1516 | /***/ 431: 1517 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1518 | 1519 | "use strict"; 1520 | 1521 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 1522 | if (k2 === undefined) k2 = k; 1523 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 1524 | }) : (function(o, m, k, k2) { 1525 | if (k2 === undefined) k2 = k; 1526 | o[k2] = m[k]; 1527 | })); 1528 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 1529 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 1530 | }) : function(o, v) { 1531 | o["default"] = v; 1532 | }); 1533 | var __importStar = (this && this.__importStar) || function (mod) { 1534 | if (mod && mod.__esModule) return mod; 1535 | var result = {}; 1536 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 1537 | __setModuleDefault(result, mod); 1538 | return result; 1539 | }; 1540 | Object.defineProperty(exports, "__esModule", { value: true }); 1541 | exports.issue = exports.issueCommand = void 0; 1542 | const os = __importStar(__webpack_require__(87)); 1543 | const utils_1 = __webpack_require__(82); 1544 | /** 1545 | * Commands 1546 | * 1547 | * Command Format: 1548 | * ::name key=value,key=value::message 1549 | * 1550 | * Examples: 1551 | * ::warning::This is the message 1552 | * ::set-env name=MY_VAR::some value 1553 | */ 1554 | function issueCommand(command, properties, message) { 1555 | const cmd = new Command(command, properties, message); 1556 | process.stdout.write(cmd.toString() + os.EOL); 1557 | } 1558 | exports.issueCommand = issueCommand; 1559 | function issue(name, message = '') { 1560 | issueCommand(name, {}, message); 1561 | } 1562 | exports.issue = issue; 1563 | const CMD_STRING = '::'; 1564 | class Command { 1565 | constructor(command, properties, message) { 1566 | if (!command) { 1567 | command = 'missing.command'; 1568 | } 1569 | this.command = command; 1570 | this.properties = properties; 1571 | this.message = message; 1572 | } 1573 | toString() { 1574 | let cmdStr = CMD_STRING + this.command; 1575 | if (this.properties && Object.keys(this.properties).length > 0) { 1576 | cmdStr += ' '; 1577 | let first = true; 1578 | for (const key in this.properties) { 1579 | if (this.properties.hasOwnProperty(key)) { 1580 | const val = this.properties[key]; 1581 | if (val) { 1582 | if (first) { 1583 | first = false; 1584 | } 1585 | else { 1586 | cmdStr += ','; 1587 | } 1588 | cmdStr += `${key}=${escapeProperty(val)}`; 1589 | } 1590 | } 1591 | } 1592 | } 1593 | cmdStr += `${CMD_STRING}${escapeData(this.message)}`; 1594 | return cmdStr; 1595 | } 1596 | } 1597 | function escapeData(s) { 1598 | return utils_1.toCommandValue(s) 1599 | .replace(/%/g, '%25') 1600 | .replace(/\r/g, '%0D') 1601 | .replace(/\n/g, '%0A'); 1602 | } 1603 | function escapeProperty(s) { 1604 | return utils_1.toCommandValue(s) 1605 | .replace(/%/g, '%25') 1606 | .replace(/\r/g, '%0D') 1607 | .replace(/\n/g, '%0A') 1608 | .replace(/:/g, '%3A') 1609 | .replace(/,/g, '%2C'); 1610 | } 1611 | //# sourceMappingURL=command.js.map 1612 | 1613 | /***/ }), 1614 | 1615 | /***/ 456: 1616 | /***/ (function(__unusedmodule, exports) { 1617 | 1618 | "use strict"; 1619 | 1620 | 1621 | Object.defineProperty(exports, "__esModule", { 1622 | value: true 1623 | }); 1624 | exports.default = void 0; 1625 | var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; 1626 | exports.default = _default; 1627 | 1628 | /***/ }), 1629 | 1630 | /***/ 470: 1631 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1632 | 1633 | "use strict"; 1634 | 1635 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 1636 | if (k2 === undefined) k2 = k; 1637 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 1638 | }) : (function(o, m, k, k2) { 1639 | if (k2 === undefined) k2 = k; 1640 | o[k2] = m[k]; 1641 | })); 1642 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 1643 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 1644 | }) : function(o, v) { 1645 | o["default"] = v; 1646 | }); 1647 | var __importStar = (this && this.__importStar) || function (mod) { 1648 | if (mod && mod.__esModule) return mod; 1649 | var result = {}; 1650 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 1651 | __setModuleDefault(result, mod); 1652 | return result; 1653 | }; 1654 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 1655 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 1656 | return new (P || (P = Promise))(function (resolve, reject) { 1657 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 1658 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 1659 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 1660 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 1661 | }); 1662 | }; 1663 | Object.defineProperty(exports, "__esModule", { value: true }); 1664 | exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; 1665 | const command_1 = __webpack_require__(431); 1666 | const file_command_1 = __webpack_require__(102); 1667 | const utils_1 = __webpack_require__(82); 1668 | const os = __importStar(__webpack_require__(87)); 1669 | const path = __importStar(__webpack_require__(622)); 1670 | const uuid_1 = __webpack_require__(62); 1671 | const oidc_utils_1 = __webpack_require__(742); 1672 | /** 1673 | * The code to exit an action 1674 | */ 1675 | var ExitCode; 1676 | (function (ExitCode) { 1677 | /** 1678 | * A code indicating that the action was successful 1679 | */ 1680 | ExitCode[ExitCode["Success"] = 0] = "Success"; 1681 | /** 1682 | * A code indicating that the action was a failure 1683 | */ 1684 | ExitCode[ExitCode["Failure"] = 1] = "Failure"; 1685 | })(ExitCode = exports.ExitCode || (exports.ExitCode = {})); 1686 | //----------------------------------------------------------------------- 1687 | // Variables 1688 | //----------------------------------------------------------------------- 1689 | /** 1690 | * Sets env variable for this action and future actions in the job 1691 | * @param name the name of the variable to set 1692 | * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify 1693 | */ 1694 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 1695 | function exportVariable(name, val) { 1696 | const convertedVal = utils_1.toCommandValue(val); 1697 | process.env[name] = convertedVal; 1698 | const filePath = process.env['GITHUB_ENV'] || ''; 1699 | if (filePath) { 1700 | const delimiter = `ghadelimiter_${uuid_1.v4()}`; 1701 | // These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter. 1702 | if (name.includes(delimiter)) { 1703 | throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`); 1704 | } 1705 | if (convertedVal.includes(delimiter)) { 1706 | throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`); 1707 | } 1708 | const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; 1709 | file_command_1.issueCommand('ENV', commandValue); 1710 | } 1711 | else { 1712 | command_1.issueCommand('set-env', { name }, convertedVal); 1713 | } 1714 | } 1715 | exports.exportVariable = exportVariable; 1716 | /** 1717 | * Registers a secret which will get masked from logs 1718 | * @param secret value of the secret 1719 | */ 1720 | function setSecret(secret) { 1721 | command_1.issueCommand('add-mask', {}, secret); 1722 | } 1723 | exports.setSecret = setSecret; 1724 | /** 1725 | * Prepends inputPath to the PATH (for this action and future actions) 1726 | * @param inputPath 1727 | */ 1728 | function addPath(inputPath) { 1729 | const filePath = process.env['GITHUB_PATH'] || ''; 1730 | if (filePath) { 1731 | file_command_1.issueCommand('PATH', inputPath); 1732 | } 1733 | else { 1734 | command_1.issueCommand('add-path', {}, inputPath); 1735 | } 1736 | process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`; 1737 | } 1738 | exports.addPath = addPath; 1739 | /** 1740 | * Gets the value of an input. 1741 | * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed. 1742 | * Returns an empty string if the value is not defined. 1743 | * 1744 | * @param name name of the input to get 1745 | * @param options optional. See InputOptions. 1746 | * @returns string 1747 | */ 1748 | function getInput(name, options) { 1749 | const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || ''; 1750 | if (options && options.required && !val) { 1751 | throw new Error(`Input required and not supplied: ${name}`); 1752 | } 1753 | if (options && options.trimWhitespace === false) { 1754 | return val; 1755 | } 1756 | return val.trim(); 1757 | } 1758 | exports.getInput = getInput; 1759 | /** 1760 | * Gets the values of an multiline input. Each value is also trimmed. 1761 | * 1762 | * @param name name of the input to get 1763 | * @param options optional. See InputOptions. 1764 | * @returns string[] 1765 | * 1766 | */ 1767 | function getMultilineInput(name, options) { 1768 | const inputs = getInput(name, options) 1769 | .split('\n') 1770 | .filter(x => x !== ''); 1771 | return inputs; 1772 | } 1773 | exports.getMultilineInput = getMultilineInput; 1774 | /** 1775 | * Gets the input value of the boolean type in the YAML 1.2 "core schema" specification. 1776 | * Support boolean input list: `true | True | TRUE | false | False | FALSE` . 1777 | * The return value is also in boolean type. 1778 | * ref: https://yaml.org/spec/1.2/spec.html#id2804923 1779 | * 1780 | * @param name name of the input to get 1781 | * @param options optional. See InputOptions. 1782 | * @returns boolean 1783 | */ 1784 | function getBooleanInput(name, options) { 1785 | const trueValue = ['true', 'True', 'TRUE']; 1786 | const falseValue = ['false', 'False', 'FALSE']; 1787 | const val = getInput(name, options); 1788 | if (trueValue.includes(val)) 1789 | return true; 1790 | if (falseValue.includes(val)) 1791 | return false; 1792 | throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` + 1793 | `Support boolean input list: \`true | True | TRUE | false | False | FALSE\``); 1794 | } 1795 | exports.getBooleanInput = getBooleanInput; 1796 | /** 1797 | * Sets the value of an output. 1798 | * 1799 | * @param name name of the output to set 1800 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 1801 | */ 1802 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 1803 | function setOutput(name, value) { 1804 | process.stdout.write(os.EOL); 1805 | command_1.issueCommand('set-output', { name }, value); 1806 | } 1807 | exports.setOutput = setOutput; 1808 | /** 1809 | * Enables or disables the echoing of commands into stdout for the rest of the step. 1810 | * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 1811 | * 1812 | */ 1813 | function setCommandEcho(enabled) { 1814 | command_1.issue('echo', enabled ? 'on' : 'off'); 1815 | } 1816 | exports.setCommandEcho = setCommandEcho; 1817 | //----------------------------------------------------------------------- 1818 | // Results 1819 | //----------------------------------------------------------------------- 1820 | /** 1821 | * Sets the action status to failed. 1822 | * When the action exits it will be with an exit code of 1 1823 | * @param message add error issue message 1824 | */ 1825 | function setFailed(message) { 1826 | process.exitCode = ExitCode.Failure; 1827 | error(message); 1828 | } 1829 | exports.setFailed = setFailed; 1830 | //----------------------------------------------------------------------- 1831 | // Logging Commands 1832 | //----------------------------------------------------------------------- 1833 | /** 1834 | * Gets whether Actions Step Debug is on or not 1835 | */ 1836 | function isDebug() { 1837 | return process.env['RUNNER_DEBUG'] === '1'; 1838 | } 1839 | exports.isDebug = isDebug; 1840 | /** 1841 | * Writes debug message to user log 1842 | * @param message debug message 1843 | */ 1844 | function debug(message) { 1845 | command_1.issueCommand('debug', {}, message); 1846 | } 1847 | exports.debug = debug; 1848 | /** 1849 | * Adds an error issue 1850 | * @param message error issue message. Errors will be converted to string via toString() 1851 | * @param properties optional properties to add to the annotation. 1852 | */ 1853 | function error(message, properties = {}) { 1854 | command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 1855 | } 1856 | exports.error = error; 1857 | /** 1858 | * Adds a warning issue 1859 | * @param message warning issue message. Errors will be converted to string via toString() 1860 | * @param properties optional properties to add to the annotation. 1861 | */ 1862 | function warning(message, properties = {}) { 1863 | command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 1864 | } 1865 | exports.warning = warning; 1866 | /** 1867 | * Adds a notice issue 1868 | * @param message notice issue message. Errors will be converted to string via toString() 1869 | * @param properties optional properties to add to the annotation. 1870 | */ 1871 | function notice(message, properties = {}) { 1872 | command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); 1873 | } 1874 | exports.notice = notice; 1875 | /** 1876 | * Writes info to log with console.log. 1877 | * @param message info message 1878 | */ 1879 | function info(message) { 1880 | process.stdout.write(message + os.EOL); 1881 | } 1882 | exports.info = info; 1883 | /** 1884 | * Begin an output group. 1885 | * 1886 | * Output until the next `groupEnd` will be foldable in this group 1887 | * 1888 | * @param name The name of the output group 1889 | */ 1890 | function startGroup(name) { 1891 | command_1.issue('group', name); 1892 | } 1893 | exports.startGroup = startGroup; 1894 | /** 1895 | * End an output group. 1896 | */ 1897 | function endGroup() { 1898 | command_1.issue('endgroup'); 1899 | } 1900 | exports.endGroup = endGroup; 1901 | /** 1902 | * Wrap an asynchronous function call in a group. 1903 | * 1904 | * Returns the same type as the function itself. 1905 | * 1906 | * @param name The name of the group 1907 | * @param fn The function to wrap in the group 1908 | */ 1909 | function group(name, fn) { 1910 | return __awaiter(this, void 0, void 0, function* () { 1911 | startGroup(name); 1912 | let result; 1913 | try { 1914 | result = yield fn(); 1915 | } 1916 | finally { 1917 | endGroup(); 1918 | } 1919 | return result; 1920 | }); 1921 | } 1922 | exports.group = group; 1923 | //----------------------------------------------------------------------- 1924 | // Wrapper action state 1925 | //----------------------------------------------------------------------- 1926 | /** 1927 | * Saves state for current action, the state can only be retrieved by this action's post job execution. 1928 | * 1929 | * @param name name of the state to store 1930 | * @param value value to store. Non-string values will be converted to a string via JSON.stringify 1931 | */ 1932 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 1933 | function saveState(name, value) { 1934 | command_1.issueCommand('save-state', { name }, value); 1935 | } 1936 | exports.saveState = saveState; 1937 | /** 1938 | * Gets the value of an state set by this action's main execution. 1939 | * 1940 | * @param name name of the state to get 1941 | * @returns string 1942 | */ 1943 | function getState(name) { 1944 | return process.env[`STATE_${name}`] || ''; 1945 | } 1946 | exports.getState = getState; 1947 | function getIDToken(aud) { 1948 | return __awaiter(this, void 0, void 0, function* () { 1949 | return yield oidc_utils_1.OidcClient.getIDToken(aud); 1950 | }); 1951 | } 1952 | exports.getIDToken = getIDToken; 1953 | /** 1954 | * Summary exports 1955 | */ 1956 | var summary_1 = __webpack_require__(665); 1957 | Object.defineProperty(exports, "summary", { enumerable: true, get: function () { return summary_1.summary; } }); 1958 | /** 1959 | * @deprecated use core.summary 1960 | */ 1961 | var summary_2 = __webpack_require__(665); 1962 | Object.defineProperty(exports, "markdownSummary", { enumerable: true, get: function () { return summary_2.markdownSummary; } }); 1963 | /** 1964 | * Path exports 1965 | */ 1966 | var path_utils_1 = __webpack_require__(573); 1967 | Object.defineProperty(exports, "toPosixPath", { enumerable: true, get: function () { return path_utils_1.toPosixPath; } }); 1968 | Object.defineProperty(exports, "toWin32Path", { enumerable: true, get: function () { return path_utils_1.toWin32Path; } }); 1969 | Object.defineProperty(exports, "toPlatformPath", { enumerable: true, get: function () { return path_utils_1.toPlatformPath; } }); 1970 | //# sourceMappingURL=core.js.map 1971 | 1972 | /***/ }), 1973 | 1974 | /***/ 498: 1975 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 1976 | 1977 | "use strict"; 1978 | 1979 | 1980 | Object.defineProperty(exports, "__esModule", { 1981 | value: true 1982 | }); 1983 | exports.default = void 0; 1984 | 1985 | var _crypto = _interopRequireDefault(__webpack_require__(417)); 1986 | 1987 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1988 | 1989 | function sha1(bytes) { 1990 | if (Array.isArray(bytes)) { 1991 | bytes = Buffer.from(bytes); 1992 | } else if (typeof bytes === 'string') { 1993 | bytes = Buffer.from(bytes, 'utf8'); 1994 | } 1995 | 1996 | return _crypto.default.createHash('sha1').update(bytes).digest(); 1997 | } 1998 | 1999 | var _default = sha1; 2000 | exports.default = _default; 2001 | 2002 | /***/ }), 2003 | 2004 | /***/ 554: 2005 | /***/ (function(__unusedmodule, exports) { 2006 | 2007 | "use strict"; 2008 | 2009 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2010 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 2011 | return new (P || (P = Promise))(function (resolve, reject) { 2012 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 2013 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 2014 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 2015 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 2016 | }); 2017 | }; 2018 | Object.defineProperty(exports, "__esModule", { value: true }); 2019 | exports.PersonalAccessTokenCredentialHandler = exports.BearerCredentialHandler = exports.BasicCredentialHandler = void 0; 2020 | class BasicCredentialHandler { 2021 | constructor(username, password) { 2022 | this.username = username; 2023 | this.password = password; 2024 | } 2025 | prepareRequest(options) { 2026 | if (!options.headers) { 2027 | throw Error('The request has no headers'); 2028 | } 2029 | options.headers['Authorization'] = `Basic ${Buffer.from(`${this.username}:${this.password}`).toString('base64')}`; 2030 | } 2031 | // This handler cannot handle 401 2032 | canHandleAuthentication() { 2033 | return false; 2034 | } 2035 | handleAuthentication() { 2036 | return __awaiter(this, void 0, void 0, function* () { 2037 | throw new Error('not implemented'); 2038 | }); 2039 | } 2040 | } 2041 | exports.BasicCredentialHandler = BasicCredentialHandler; 2042 | class BearerCredentialHandler { 2043 | constructor(token) { 2044 | this.token = token; 2045 | } 2046 | // currently implements pre-authorization 2047 | // TODO: support preAuth = false where it hooks on 401 2048 | prepareRequest(options) { 2049 | if (!options.headers) { 2050 | throw Error('The request has no headers'); 2051 | } 2052 | options.headers['Authorization'] = `Bearer ${this.token}`; 2053 | } 2054 | // This handler cannot handle 401 2055 | canHandleAuthentication() { 2056 | return false; 2057 | } 2058 | handleAuthentication() { 2059 | return __awaiter(this, void 0, void 0, function* () { 2060 | throw new Error('not implemented'); 2061 | }); 2062 | } 2063 | } 2064 | exports.BearerCredentialHandler = BearerCredentialHandler; 2065 | class PersonalAccessTokenCredentialHandler { 2066 | constructor(token) { 2067 | this.token = token; 2068 | } 2069 | // currently implements pre-authorization 2070 | // TODO: support preAuth = false where it hooks on 401 2071 | prepareRequest(options) { 2072 | if (!options.headers) { 2073 | throw Error('The request has no headers'); 2074 | } 2075 | options.headers['Authorization'] = `Basic ${Buffer.from(`PAT:${this.token}`).toString('base64')}`; 2076 | } 2077 | // This handler cannot handle 401 2078 | canHandleAuthentication() { 2079 | return false; 2080 | } 2081 | handleAuthentication() { 2082 | return __awaiter(this, void 0, void 0, function* () { 2083 | throw new Error('not implemented'); 2084 | }); 2085 | } 2086 | } 2087 | exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; 2088 | //# sourceMappingURL=auth.js.map 2089 | 2090 | /***/ }), 2091 | 2092 | /***/ 573: 2093 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2094 | 2095 | "use strict"; 2096 | 2097 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 2098 | if (k2 === undefined) k2 = k; 2099 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 2100 | }) : (function(o, m, k, k2) { 2101 | if (k2 === undefined) k2 = k; 2102 | o[k2] = m[k]; 2103 | })); 2104 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 2105 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 2106 | }) : function(o, v) { 2107 | o["default"] = v; 2108 | }); 2109 | var __importStar = (this && this.__importStar) || function (mod) { 2110 | if (mod && mod.__esModule) return mod; 2111 | var result = {}; 2112 | if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 2113 | __setModuleDefault(result, mod); 2114 | return result; 2115 | }; 2116 | Object.defineProperty(exports, "__esModule", { value: true }); 2117 | exports.toPlatformPath = exports.toWin32Path = exports.toPosixPath = void 0; 2118 | const path = __importStar(__webpack_require__(622)); 2119 | /** 2120 | * toPosixPath converts the given path to the posix form. On Windows, \\ will be 2121 | * replaced with /. 2122 | * 2123 | * @param pth. Path to transform. 2124 | * @return string Posix path. 2125 | */ 2126 | function toPosixPath(pth) { 2127 | return pth.replace(/[\\]/g, '/'); 2128 | } 2129 | exports.toPosixPath = toPosixPath; 2130 | /** 2131 | * toWin32Path converts the given path to the win32 form. On Linux, / will be 2132 | * replaced with \\. 2133 | * 2134 | * @param pth. Path to transform. 2135 | * @return string Win32 path. 2136 | */ 2137 | function toWin32Path(pth) { 2138 | return pth.replace(/[/]/g, '\\'); 2139 | } 2140 | exports.toWin32Path = toWin32Path; 2141 | /** 2142 | * toPlatformPath converts the given path to a platform-specific path. It does 2143 | * this by replacing instances of / and \ with the platform-specific path 2144 | * separator. 2145 | * 2146 | * @param pth The path to platformize. 2147 | * @return string The platform-specific path. 2148 | */ 2149 | function toPlatformPath(pth) { 2150 | return pth.replace(/[/\\]/g, path.sep); 2151 | } 2152 | exports.toPlatformPath = toPlatformPath; 2153 | //# sourceMappingURL=path-utils.js.map 2154 | 2155 | /***/ }), 2156 | 2157 | /***/ 605: 2158 | /***/ (function(module) { 2159 | 2160 | module.exports = require("http"); 2161 | 2162 | /***/ }), 2163 | 2164 | /***/ 614: 2165 | /***/ (function(module) { 2166 | 2167 | module.exports = require("events"); 2168 | 2169 | /***/ }), 2170 | 2171 | /***/ 622: 2172 | /***/ (function(module) { 2173 | 2174 | module.exports = require("path"); 2175 | 2176 | /***/ }), 2177 | 2178 | /***/ 631: 2179 | /***/ (function(module) { 2180 | 2181 | module.exports = require("net"); 2182 | 2183 | /***/ }), 2184 | 2185 | /***/ 665: 2186 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2187 | 2188 | "use strict"; 2189 | 2190 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2191 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 2192 | return new (P || (P = Promise))(function (resolve, reject) { 2193 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 2194 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 2195 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 2196 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 2197 | }); 2198 | }; 2199 | Object.defineProperty(exports, "__esModule", { value: true }); 2200 | exports.summary = exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0; 2201 | const os_1 = __webpack_require__(87); 2202 | const fs_1 = __webpack_require__(747); 2203 | const { access, appendFile, writeFile } = fs_1.promises; 2204 | exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'; 2205 | exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary'; 2206 | class Summary { 2207 | constructor() { 2208 | this._buffer = ''; 2209 | } 2210 | /** 2211 | * Finds the summary file path from the environment, rejects if env var is not found or file does not exist 2212 | * Also checks r/w permissions. 2213 | * 2214 | * @returns step summary file path 2215 | */ 2216 | filePath() { 2217 | return __awaiter(this, void 0, void 0, function* () { 2218 | if (this._filePath) { 2219 | return this._filePath; 2220 | } 2221 | const pathFromEnv = process.env[exports.SUMMARY_ENV_VAR]; 2222 | if (!pathFromEnv) { 2223 | throw new Error(`Unable to find environment variable for $${exports.SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.`); 2224 | } 2225 | try { 2226 | yield access(pathFromEnv, fs_1.constants.R_OK | fs_1.constants.W_OK); 2227 | } 2228 | catch (_a) { 2229 | throw new Error(`Unable to access summary file: '${pathFromEnv}'. Check if the file has correct read/write permissions.`); 2230 | } 2231 | this._filePath = pathFromEnv; 2232 | return this._filePath; 2233 | }); 2234 | } 2235 | /** 2236 | * Wraps content in an HTML tag, adding any HTML attributes 2237 | * 2238 | * @param {string} tag HTML tag to wrap 2239 | * @param {string | null} content content within the tag 2240 | * @param {[attribute: string]: string} attrs key-value list of HTML attributes to add 2241 | * 2242 | * @returns {string} content wrapped in HTML element 2243 | */ 2244 | wrap(tag, content, attrs = {}) { 2245 | const htmlAttrs = Object.entries(attrs) 2246 | .map(([key, value]) => ` ${key}="${value}"`) 2247 | .join(''); 2248 | if (!content) { 2249 | return `<${tag}${htmlAttrs}>`; 2250 | } 2251 | return `<${tag}${htmlAttrs}>${content}`; 2252 | } 2253 | /** 2254 | * Writes text in the buffer to the summary buffer file and empties buffer. Will append by default. 2255 | * 2256 | * @param {SummaryWriteOptions} [options] (optional) options for write operation 2257 | * 2258 | * @returns {Promise} summary instance 2259 | */ 2260 | write(options) { 2261 | return __awaiter(this, void 0, void 0, function* () { 2262 | const overwrite = !!(options === null || options === void 0 ? void 0 : options.overwrite); 2263 | const filePath = yield this.filePath(); 2264 | const writeFunc = overwrite ? writeFile : appendFile; 2265 | yield writeFunc(filePath, this._buffer, { encoding: 'utf8' }); 2266 | return this.emptyBuffer(); 2267 | }); 2268 | } 2269 | /** 2270 | * Clears the summary buffer and wipes the summary file 2271 | * 2272 | * @returns {Summary} summary instance 2273 | */ 2274 | clear() { 2275 | return __awaiter(this, void 0, void 0, function* () { 2276 | return this.emptyBuffer().write({ overwrite: true }); 2277 | }); 2278 | } 2279 | /** 2280 | * Returns the current summary buffer as a string 2281 | * 2282 | * @returns {string} string of summary buffer 2283 | */ 2284 | stringify() { 2285 | return this._buffer; 2286 | } 2287 | /** 2288 | * If the summary buffer is empty 2289 | * 2290 | * @returns {boolen} true if the buffer is empty 2291 | */ 2292 | isEmptyBuffer() { 2293 | return this._buffer.length === 0; 2294 | } 2295 | /** 2296 | * Resets the summary buffer without writing to summary file 2297 | * 2298 | * @returns {Summary} summary instance 2299 | */ 2300 | emptyBuffer() { 2301 | this._buffer = ''; 2302 | return this; 2303 | } 2304 | /** 2305 | * Adds raw text to the summary buffer 2306 | * 2307 | * @param {string} text content to add 2308 | * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false) 2309 | * 2310 | * @returns {Summary} summary instance 2311 | */ 2312 | addRaw(text, addEOL = false) { 2313 | this._buffer += text; 2314 | return addEOL ? this.addEOL() : this; 2315 | } 2316 | /** 2317 | * Adds the operating system-specific end-of-line marker to the buffer 2318 | * 2319 | * @returns {Summary} summary instance 2320 | */ 2321 | addEOL() { 2322 | return this.addRaw(os_1.EOL); 2323 | } 2324 | /** 2325 | * Adds an HTML codeblock to the summary buffer 2326 | * 2327 | * @param {string} code content to render within fenced code block 2328 | * @param {string} lang (optional) language to syntax highlight code 2329 | * 2330 | * @returns {Summary} summary instance 2331 | */ 2332 | addCodeBlock(code, lang) { 2333 | const attrs = Object.assign({}, (lang && { lang })); 2334 | const element = this.wrap('pre', this.wrap('code', code), attrs); 2335 | return this.addRaw(element).addEOL(); 2336 | } 2337 | /** 2338 | * Adds an HTML list to the summary buffer 2339 | * 2340 | * @param {string[]} items list of items to render 2341 | * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false) 2342 | * 2343 | * @returns {Summary} summary instance 2344 | */ 2345 | addList(items, ordered = false) { 2346 | const tag = ordered ? 'ol' : 'ul'; 2347 | const listItems = items.map(item => this.wrap('li', item)).join(''); 2348 | const element = this.wrap(tag, listItems); 2349 | return this.addRaw(element).addEOL(); 2350 | } 2351 | /** 2352 | * Adds an HTML table to the summary buffer 2353 | * 2354 | * @param {SummaryTableCell[]} rows table rows 2355 | * 2356 | * @returns {Summary} summary instance 2357 | */ 2358 | addTable(rows) { 2359 | const tableBody = rows 2360 | .map(row => { 2361 | const cells = row 2362 | .map(cell => { 2363 | if (typeof cell === 'string') { 2364 | return this.wrap('td', cell); 2365 | } 2366 | const { header, data, colspan, rowspan } = cell; 2367 | const tag = header ? 'th' : 'td'; 2368 | const attrs = Object.assign(Object.assign({}, (colspan && { colspan })), (rowspan && { rowspan })); 2369 | return this.wrap(tag, data, attrs); 2370 | }) 2371 | .join(''); 2372 | return this.wrap('tr', cells); 2373 | }) 2374 | .join(''); 2375 | const element = this.wrap('table', tableBody); 2376 | return this.addRaw(element).addEOL(); 2377 | } 2378 | /** 2379 | * Adds a collapsable HTML details element to the summary buffer 2380 | * 2381 | * @param {string} label text for the closed state 2382 | * @param {string} content collapsable content 2383 | * 2384 | * @returns {Summary} summary instance 2385 | */ 2386 | addDetails(label, content) { 2387 | const element = this.wrap('details', this.wrap('summary', label) + content); 2388 | return this.addRaw(element).addEOL(); 2389 | } 2390 | /** 2391 | * Adds an HTML image tag to the summary buffer 2392 | * 2393 | * @param {string} src path to the image you to embed 2394 | * @param {string} alt text description of the image 2395 | * @param {SummaryImageOptions} options (optional) addition image attributes 2396 | * 2397 | * @returns {Summary} summary instance 2398 | */ 2399 | addImage(src, alt, options) { 2400 | const { width, height } = options || {}; 2401 | const attrs = Object.assign(Object.assign({}, (width && { width })), (height && { height })); 2402 | const element = this.wrap('img', null, Object.assign({ src, alt }, attrs)); 2403 | return this.addRaw(element).addEOL(); 2404 | } 2405 | /** 2406 | * Adds an HTML section heading element 2407 | * 2408 | * @param {string} text heading text 2409 | * @param {number | string} [level=1] (optional) the heading level, default: 1 2410 | * 2411 | * @returns {Summary} summary instance 2412 | */ 2413 | addHeading(text, level) { 2414 | const tag = `h${level}`; 2415 | const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag) 2416 | ? tag 2417 | : 'h1'; 2418 | const element = this.wrap(allowedTag, text); 2419 | return this.addRaw(element).addEOL(); 2420 | } 2421 | /** 2422 | * Adds an HTML thematic break (
) to the summary buffer 2423 | * 2424 | * @returns {Summary} summary instance 2425 | */ 2426 | addSeparator() { 2427 | const element = this.wrap('hr', null); 2428 | return this.addRaw(element).addEOL(); 2429 | } 2430 | /** 2431 | * Adds an HTML line break (
) to the summary buffer 2432 | * 2433 | * @returns {Summary} summary instance 2434 | */ 2435 | addBreak() { 2436 | const element = this.wrap('br', null); 2437 | return this.addRaw(element).addEOL(); 2438 | } 2439 | /** 2440 | * Adds an HTML blockquote to the summary buffer 2441 | * 2442 | * @param {string} text quote text 2443 | * @param {string} cite (optional) citation url 2444 | * 2445 | * @returns {Summary} summary instance 2446 | */ 2447 | addQuote(text, cite) { 2448 | const attrs = Object.assign({}, (cite && { cite })); 2449 | const element = this.wrap('blockquote', text, attrs); 2450 | return this.addRaw(element).addEOL(); 2451 | } 2452 | /** 2453 | * Adds an HTML anchor tag to the summary buffer 2454 | * 2455 | * @param {string} text link text/content 2456 | * @param {string} href hyperlink 2457 | * 2458 | * @returns {Summary} summary instance 2459 | */ 2460 | addLink(text, href) { 2461 | const element = this.wrap('a', text, { href }); 2462 | return this.addRaw(element).addEOL(); 2463 | } 2464 | } 2465 | const _summary = new Summary(); 2466 | /** 2467 | * @deprecated use `core.summary` 2468 | */ 2469 | exports.markdownSummary = _summary; 2470 | exports.summary = _summary; 2471 | //# sourceMappingURL=summary.js.map 2472 | 2473 | /***/ }), 2474 | 2475 | /***/ 669: 2476 | /***/ (function(module) { 2477 | 2478 | module.exports = require("util"); 2479 | 2480 | /***/ }), 2481 | 2482 | /***/ 695: 2483 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2484 | 2485 | "use strict"; 2486 | 2487 | 2488 | Object.defineProperty(exports, "__esModule", { 2489 | value: true 2490 | }); 2491 | exports.default = void 0; 2492 | 2493 | var _validate = _interopRequireDefault(__webpack_require__(78)); 2494 | 2495 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2496 | 2497 | function version(uuid) { 2498 | if (!(0, _validate.default)(uuid)) { 2499 | throw TypeError('Invalid UUID'); 2500 | } 2501 | 2502 | return parseInt(uuid.substr(14, 1), 16); 2503 | } 2504 | 2505 | var _default = version; 2506 | exports.default = _default; 2507 | 2508 | /***/ }), 2509 | 2510 | /***/ 733: 2511 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2512 | 2513 | "use strict"; 2514 | 2515 | 2516 | Object.defineProperty(exports, "__esModule", { 2517 | value: true 2518 | }); 2519 | exports.default = void 0; 2520 | 2521 | var _rng = _interopRequireDefault(__webpack_require__(844)); 2522 | 2523 | var _stringify = _interopRequireDefault(__webpack_require__(411)); 2524 | 2525 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2526 | 2527 | function v4(options, buf, offset) { 2528 | options = options || {}; 2529 | 2530 | const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` 2531 | 2532 | 2533 | rnds[6] = rnds[6] & 0x0f | 0x40; 2534 | rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided 2535 | 2536 | if (buf) { 2537 | offset = offset || 0; 2538 | 2539 | for (let i = 0; i < 16; ++i) { 2540 | buf[offset + i] = rnds[i]; 2541 | } 2542 | 2543 | return buf; 2544 | } 2545 | 2546 | return (0, _stringify.default)(rnds); 2547 | } 2548 | 2549 | var _default = v4; 2550 | exports.default = _default; 2551 | 2552 | /***/ }), 2553 | 2554 | /***/ 742: 2555 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2556 | 2557 | "use strict"; 2558 | 2559 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 2560 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 2561 | return new (P || (P = Promise))(function (resolve, reject) { 2562 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 2563 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 2564 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 2565 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 2566 | }); 2567 | }; 2568 | Object.defineProperty(exports, "__esModule", { value: true }); 2569 | exports.OidcClient = void 0; 2570 | const http_client_1 = __webpack_require__(425); 2571 | const auth_1 = __webpack_require__(554); 2572 | const core_1 = __webpack_require__(470); 2573 | class OidcClient { 2574 | static createHttpClient(allowRetry = true, maxRetry = 10) { 2575 | const requestOptions = { 2576 | allowRetries: allowRetry, 2577 | maxRetries: maxRetry 2578 | }; 2579 | return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions); 2580 | } 2581 | static getRequestToken() { 2582 | const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']; 2583 | if (!token) { 2584 | throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'); 2585 | } 2586 | return token; 2587 | } 2588 | static getIDTokenUrl() { 2589 | const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']; 2590 | if (!runtimeUrl) { 2591 | throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'); 2592 | } 2593 | return runtimeUrl; 2594 | } 2595 | static getCall(id_token_url) { 2596 | var _a; 2597 | return __awaiter(this, void 0, void 0, function* () { 2598 | const httpclient = OidcClient.createHttpClient(); 2599 | const res = yield httpclient 2600 | .getJson(id_token_url) 2601 | .catch(error => { 2602 | throw new Error(`Failed to get ID Token. \n 2603 | Error Code : ${error.statusCode}\n 2604 | Error Message: ${error.result.message}`); 2605 | }); 2606 | const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; 2607 | if (!id_token) { 2608 | throw new Error('Response json body do not have ID Token field'); 2609 | } 2610 | return id_token; 2611 | }); 2612 | } 2613 | static getIDToken(audience) { 2614 | return __awaiter(this, void 0, void 0, function* () { 2615 | try { 2616 | // New ID Token is requested from action service 2617 | let id_token_url = OidcClient.getIDTokenUrl(); 2618 | if (audience) { 2619 | const encodedAudience = encodeURIComponent(audience); 2620 | id_token_url = `${id_token_url}&audience=${encodedAudience}`; 2621 | } 2622 | core_1.debug(`ID token url is ${id_token_url}`); 2623 | const id_token = yield OidcClient.getCall(id_token_url); 2624 | core_1.setSecret(id_token); 2625 | return id_token; 2626 | } 2627 | catch (error) { 2628 | throw new Error(`Error message: ${error.message}`); 2629 | } 2630 | }); 2631 | } 2632 | } 2633 | exports.OidcClient = OidcClient; 2634 | //# sourceMappingURL=oidc-utils.js.map 2635 | 2636 | /***/ }), 2637 | 2638 | /***/ 747: 2639 | /***/ (function(module) { 2640 | 2641 | module.exports = require("fs"); 2642 | 2643 | /***/ }), 2644 | 2645 | /***/ 803: 2646 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2647 | 2648 | "use strict"; 2649 | 2650 | 2651 | Object.defineProperty(exports, "__esModule", { 2652 | value: true 2653 | }); 2654 | exports.default = void 0; 2655 | 2656 | var _crypto = _interopRequireDefault(__webpack_require__(417)); 2657 | 2658 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2659 | 2660 | function md5(bytes) { 2661 | if (Array.isArray(bytes)) { 2662 | bytes = Buffer.from(bytes); 2663 | } else if (typeof bytes === 'string') { 2664 | bytes = Buffer.from(bytes, 'utf8'); 2665 | } 2666 | 2667 | return _crypto.default.createHash('md5').update(bytes).digest(); 2668 | } 2669 | 2670 | var _default = md5; 2671 | exports.default = _default; 2672 | 2673 | /***/ }), 2674 | 2675 | /***/ 844: 2676 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2677 | 2678 | "use strict"; 2679 | 2680 | 2681 | Object.defineProperty(exports, "__esModule", { 2682 | value: true 2683 | }); 2684 | exports.default = rng; 2685 | 2686 | var _crypto = _interopRequireDefault(__webpack_require__(417)); 2687 | 2688 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2689 | 2690 | const rnds8Pool = new Uint8Array(256); // # of random values to pre-allocate 2691 | 2692 | let poolPtr = rnds8Pool.length; 2693 | 2694 | function rng() { 2695 | if (poolPtr > rnds8Pool.length - 16) { 2696 | _crypto.default.randomFillSync(rnds8Pool); 2697 | 2698 | poolPtr = 0; 2699 | } 2700 | 2701 | return rnds8Pool.slice(poolPtr, poolPtr += 16); 2702 | } 2703 | 2704 | /***/ }), 2705 | 2706 | /***/ 893: 2707 | /***/ (function(__unusedmodule, exports, __webpack_require__) { 2708 | 2709 | "use strict"; 2710 | 2711 | 2712 | Object.defineProperty(exports, "__esModule", { 2713 | value: true 2714 | }); 2715 | exports.default = void 0; 2716 | 2717 | var _rng = _interopRequireDefault(__webpack_require__(844)); 2718 | 2719 | var _stringify = _interopRequireDefault(__webpack_require__(411)); 2720 | 2721 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2722 | 2723 | // **`v1()` - Generate time-based UUID** 2724 | // 2725 | // Inspired by https://github.com/LiosK/UUID.js 2726 | // and http://docs.python.org/library/uuid.html 2727 | let _nodeId; 2728 | 2729 | let _clockseq; // Previous uuid creation time 2730 | 2731 | 2732 | let _lastMSecs = 0; 2733 | let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details 2734 | 2735 | function v1(options, buf, offset) { 2736 | let i = buf && offset || 0; 2737 | const b = buf || new Array(16); 2738 | options = options || {}; 2739 | let node = options.node || _nodeId; 2740 | let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not 2741 | // specified. We do this lazily to minimize issues related to insufficient 2742 | // system entropy. See #189 2743 | 2744 | if (node == null || clockseq == null) { 2745 | const seedBytes = options.random || (options.rng || _rng.default)(); 2746 | 2747 | if (node == null) { 2748 | // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) 2749 | node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; 2750 | } 2751 | 2752 | if (clockseq == null) { 2753 | // Per 4.2.2, randomize (14 bit) clockseq 2754 | clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; 2755 | } 2756 | } // UUID timestamps are 100 nano-second units since the Gregorian epoch, 2757 | // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so 2758 | // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' 2759 | // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. 2760 | 2761 | 2762 | let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock 2763 | // cycle to simulate higher resolution clock 2764 | 2765 | let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) 2766 | 2767 | const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression 2768 | 2769 | if (dt < 0 && options.clockseq === undefined) { 2770 | clockseq = clockseq + 1 & 0x3fff; 2771 | } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new 2772 | // time interval 2773 | 2774 | 2775 | if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { 2776 | nsecs = 0; 2777 | } // Per 4.2.1.2 Throw error if too many uuids are requested 2778 | 2779 | 2780 | if (nsecs >= 10000) { 2781 | throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); 2782 | } 2783 | 2784 | _lastMSecs = msecs; 2785 | _lastNSecs = nsecs; 2786 | _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch 2787 | 2788 | msecs += 12219292800000; // `time_low` 2789 | 2790 | const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; 2791 | b[i++] = tl >>> 24 & 0xff; 2792 | b[i++] = tl >>> 16 & 0xff; 2793 | b[i++] = tl >>> 8 & 0xff; 2794 | b[i++] = tl & 0xff; // `time_mid` 2795 | 2796 | const tmh = msecs / 0x100000000 * 10000 & 0xfffffff; 2797 | b[i++] = tmh >>> 8 & 0xff; 2798 | b[i++] = tmh & 0xff; // `time_high_and_version` 2799 | 2800 | b[i++] = tmh >>> 24 & 0xf | 0x10; // include version 2801 | 2802 | b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) 2803 | 2804 | b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` 2805 | 2806 | b[i++] = clockseq & 0xff; // `node` 2807 | 2808 | for (let n = 0; n < 6; ++n) { 2809 | b[i + n] = node[n]; 2810 | } 2811 | 2812 | return buf || (0, _stringify.default)(b); 2813 | } 2814 | 2815 | var _default = v1; 2816 | exports.default = _default; 2817 | 2818 | /***/ }), 2819 | 2820 | /***/ 972: 2821 | /***/ (function(module, __unusedexports, __webpack_require__) { 2822 | 2823 | const os = __webpack_require__(87); 2824 | const core = __webpack_require__(470); 2825 | 2826 | const defaults = (process.env['OS'] != 'Windows_NT') ? { 2827 | // Use getent() system call, since this is what ssh does; makes a difference in Docker-based 2828 | // Action runs, where $HOME is different from the pwent 2829 | homePath: os.userInfo().homedir, 2830 | sshAgentCmdDefault: 'ssh-agent', 2831 | sshAddCmdDefault: 'ssh-add', 2832 | gitCmdDefault: 'git' 2833 | } : { 2834 | // Assuming GitHub hosted `windows-*` runners for now 2835 | homePath: os.homedir(), 2836 | sshAgentCmdDefault: 'c://progra~1//git//usr//bin//ssh-agent.exe', 2837 | sshAddCmdDefault: 'c://progra~1//git//usr//bin//ssh-add.exe', 2838 | gitCmdDefault: 'c://progra~1//git//bin//git.exe' 2839 | }; 2840 | 2841 | const sshAgentCmdInput = core.getInput('ssh-agent-cmd'); 2842 | const sshAddCmdInput = core.getInput('ssh-add-cmd'); 2843 | const gitCmdInput = core.getInput('git-cmd'); 2844 | 2845 | module.exports = { 2846 | homePath: defaults.homePath, 2847 | sshAgentCmd: sshAgentCmdInput !== '' ? sshAgentCmdInput : defaults.sshAgentCmdDefault, 2848 | sshAddCmd: sshAddCmdInput !== '' ? sshAddCmdInput : defaults.sshAddCmdDefault, 2849 | gitCmd: gitCmdInput !== '' ? gitCmdInput : defaults.gitCmdDefault, 2850 | }; 2851 | 2852 | 2853 | /***/ }) 2854 | 2855 | /******/ }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const core = require('@actions/core'); 2 | const child_process = require('child_process'); 3 | const fs = require('fs'); 4 | const crypto = require('crypto'); 5 | const { homePath, sshAgentCmd, sshAddCmd, gitCmd } = require('./paths.js'); 6 | 7 | try { 8 | const privateKey = core.getInput('ssh-private-key'); 9 | const logPublicKey = core.getBooleanInput('log-public-key', {default: true}); 10 | 11 | if (!privateKey) { 12 | core.setFailed("The ssh-private-key argument is empty. Maybe the secret has not been configured, or you are using a wrong secret name in your workflow file."); 13 | 14 | return; 15 | } 16 | 17 | const homeSsh = homePath + '/.ssh'; 18 | fs.mkdirSync(homeSsh, { recursive: true }); 19 | 20 | console.log("Starting ssh-agent"); 21 | 22 | const authSock = core.getInput('ssh-auth-sock'); 23 | const sshAgentArgs = (authSock && authSock.length > 0) ? ['-a', authSock] : []; 24 | 25 | // Extract auth socket path and agent pid and set them as job variables 26 | child_process.execFileSync(sshAgentCmd, sshAgentArgs).toString().split("\n").forEach(function(line) { 27 | const matches = /^(SSH_AUTH_SOCK|SSH_AGENT_PID)=(.*); export \1/.exec(line); 28 | 29 | if (matches && matches.length > 0) { 30 | // This will also set process.env accordingly, so changes take effect for this script 31 | core.exportVariable(matches[1], matches[2]) 32 | console.log(`${matches[1]}=${matches[2]}`); 33 | } 34 | }); 35 | 36 | console.log("Adding private key(s) to agent"); 37 | 38 | privateKey.split(/(?=-----BEGIN)/).forEach(function(key) { 39 | child_process.execFileSync(sshAddCmd, ['-'], { input: key.trim() + "\n" }); 40 | }); 41 | 42 | console.log("Key(s) added:"); 43 | 44 | child_process.execFileSync(sshAddCmd, ['-l'], { stdio: 'inherit' }); 45 | 46 | console.log('Configuring deployment key(s)'); 47 | 48 | child_process.execFileSync(sshAddCmd, ['-L']).toString().trim().split(/\r?\n/).forEach(function(key) { 49 | const parts = key.match(/\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+)/i); 50 | 51 | if (!parts) { 52 | if (logPublicKey) { 53 | console.log(`Comment for (public) key '${key}' does not match GitHub URL pattern. Not treating it as a GitHub deploy key.`); 54 | } 55 | return; 56 | } 57 | 58 | const sha256 = crypto.createHash('sha256').update(key).digest('hex'); 59 | const ownerAndRepo = parts[1].replace(/\.git$/, ''); 60 | 61 | fs.writeFileSync(`${homeSsh}/key-${sha256}`, key + "\n", { mode: '600' }); 62 | 63 | child_process.execSync(`${gitCmd} config --global --replace-all url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`); 64 | child_process.execSync(`${gitCmd} config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`); 65 | child_process.execSync(`${gitCmd} config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`); 66 | 67 | const sshConfig = `\nHost key-${sha256}.github.com\n` 68 | + ` HostName github.com\n` 69 | + ` IdentityFile ${homeSsh}/key-${sha256}\n` 70 | + ` IdentitiesOnly yes\n`; 71 | 72 | fs.appendFileSync(`${homeSsh}/config`, sshConfig); 73 | 74 | console.log(`Added deploy-key mapping: Use identity '${homeSsh}/key-${sha256}' for GitHub repository ${ownerAndRepo}`); 75 | }); 76 | 77 | } catch (error) { 78 | 79 | if (error.code == 'ENOENT') { 80 | console.log(`The '${error.path}' executable could not be found. Please make sure it is on your PATH and/or the necessary packages are installed.`); 81 | console.log(`PATH is set to: ${process.env.PATH}`); 82 | } 83 | 84 | core.setFailed(error.message); 85 | } 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webfactory-action-ssh-agent", 3 | "repository": "git@github.com:webfactory/ssh-agent.git", 4 | "description": "GitHub Action to set up ssh-agent with a private SSH key", 5 | "version": "0.7.0", 6 | "main": "index.js", 7 | "author": "webfactory GmbH ", 8 | "license": "MIT", 9 | "devDependencies": { 10 | "@actions/core": "^1.9.1", 11 | "@zeit/ncc": "^0.20.5" 12 | }, 13 | "scripts": { 14 | "build": "node scripts/build.js" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /paths.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const core = require('@actions/core'); 3 | 4 | const defaults = (process.env['OS'] != 'Windows_NT') ? { 5 | // We use os.userInfo() rather than os.homedir(), since it uses the getpwuid() system call to get the user's home directory (see https://nodejs.org/api/os.html#osuserinfooptions). 6 | // This mimics the way openssh derives the home directory for locating config files (see https://github.com/openssh/openssh-portable/blob/826483d51a9fee60703298bbf839d9ce37943474/ssh.c#L710); 7 | // Makes a difference in Docker-based Action runs, when $HOME is different from what getpwuid() returns (which is based on the entry in /etc/passwd) 8 | homePath: os.userInfo().homedir, 9 | sshAgentCmdDefault: 'ssh-agent', 10 | sshAddCmdDefault: 'ssh-add', 11 | gitCmdDefault: 'git' 12 | } : { 13 | // Assuming GitHub hosted `windows-*` runners for now 14 | homePath: os.homedir(), 15 | sshAgentCmdDefault: 'c://progra~1//git//usr//bin//ssh-agent.exe', 16 | sshAddCmdDefault: 'c://progra~1//git//usr//bin//ssh-add.exe', 17 | gitCmdDefault: 'c://progra~1//git//bin//git.exe' 18 | }; 19 | 20 | const sshAgentCmdInput = core.getInput('ssh-agent-cmd'); 21 | const sshAddCmdInput = core.getInput('ssh-add-cmd'); 22 | const gitCmdInput = core.getInput('git-cmd'); 23 | 24 | module.exports = { 25 | homePath: defaults.homePath, 26 | sshAgentCmd: sshAgentCmdInput !== '' ? sshAgentCmdInput : defaults.sshAgentCmdDefault, 27 | sshAddCmd: sshAddCmdInput !== '' ? sshAddCmdInput : defaults.sshAddCmdDefault, 28 | gitCmd: gitCmdInput !== '' ? gitCmdInput : defaults.gitCmdDefault, 29 | }; 30 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const { execSync } = require('child_process') 2 | const path = require('path') 3 | const fs = require('fs') 4 | const process = require('process') 5 | 6 | const buildDir = path.join(process.cwd(), 'build') 7 | const distDir = path.join(process.cwd(), 'dist') 8 | 9 | const buildIndexJs = path.join(buildDir, 'index.js') 10 | const distIndexJs = path.join(distDir, 'index.js') 11 | const distCleanupJs = path.join(distDir, 'cleanup.js') 12 | 13 | var ncc = `./node_modules/.bin/ncc`; 14 | if (process.platform === "win32") { 15 | ncc = `.\\node_modules\\.bin\\ncc.cmd`; 16 | } 17 | 18 | if (!fs.existsSync(buildDir)) { 19 | fs.mkdirSync(buildDir) 20 | } 21 | 22 | // Build the main index.js file 23 | console.log('Building index.js...') 24 | execSync(`${ncc} build index.js -q -o ${buildDir}`) 25 | if (fs.existsSync(distIndexJs)) { 26 | fs.unlinkSync(distIndexJs) 27 | } 28 | fs.renameSync(buildIndexJs, distIndexJs) 29 | 30 | // Build the cleanup.js file 31 | console.log('Building cleanup.js...') 32 | execSync(`${ncc} build cleanup.js -q -o ${buildDir}`) 33 | if (fs.existsSync(distCleanupJs)) { 34 | fs.unlinkSync(distCleanupJs) 35 | } 36 | fs.renameSync(buildIndexJs, distCleanupJs) 37 | 38 | console.log('Cleaning up...') 39 | fs.rmdirSync(buildDir) 40 | 41 | console.log('Done') 42 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@actions/core@^1.9.1": 6 | "integrity" "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==" 7 | "resolved" "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz" 8 | "version" "1.9.1" 9 | dependencies: 10 | "@actions/http-client" "^2.0.1" 11 | "uuid" "^8.3.2" 12 | 13 | "@actions/http-client@^2.0.1": 14 | "integrity" "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==" 15 | "resolved" "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz" 16 | "version" "2.0.1" 17 | dependencies: 18 | "tunnel" "^0.0.6" 19 | 20 | "@zeit/ncc@^0.20.5": 21 | "integrity" "sha512-XU6uzwvv95DqxciQx+aOLhbyBx/13ky+RK1y88Age9Du3BlA4mMPCy13BGjayOrrumOzlq1XV3SD/BWiZENXlw==" 22 | "resolved" "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.20.5.tgz" 23 | "version" "0.20.5" 24 | 25 | "tunnel@^0.0.6": 26 | "integrity" "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" 27 | "resolved" "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz" 28 | "version" "0.0.6" 29 | 30 | "uuid@^8.3.2": 31 | "integrity" "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 32 | "resolved" "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" 33 | "version" "8.3.2" 34 | --------------------------------------------------------------------------------