-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(github-actions): introduce actions for safely deploying previews
This action will be used to supersede/simplify the existing Github action workflows in `angular/components` and the AIO docker VM setup.
- Loading branch information
1 parent
361be06
commit a818bed
Showing
15 changed files
with
11,399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
load("//tools:defaults.bzl", "ts_library") | ||
|
||
package(default_visibility = ["//github-actions/deploy-previews:__subpackages__"]) | ||
|
||
ts_library( | ||
name = "constants_lib", | ||
srcs = ["constants.ts"], | ||
deps = [], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
export const artifactMetadata = { | ||
'pull-number': './__metadata__pull_number.txt', | ||
'build-revision': './__metadata__build_revision.txt', | ||
} as const; |
10 changes: 10 additions & 0 deletions
10
github-actions/deploy-previews/pack-and-upload-artifact/BUILD.bazel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
load("//tools:defaults.bzl", "esbuild_checked_in") | ||
|
||
esbuild_checked_in( | ||
name = "inject-artifact-metadata", | ||
entry_point = "//github-actions/deploy-previews/pack-and-upload-artifact/lib:inject-artifact-metadata.ts", | ||
target = "node16", | ||
deps = [ | ||
"//github-actions/deploy-previews/pack-and-upload-artifact/lib:inject_artifact_metadata_lib", | ||
], | ||
) |
49 changes: 49 additions & 0 deletions
49
github-actions/deploy-previews/pack-and-upload-artifact/action.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: Pack and upload Artifacts to Workflow | ||
author: 'Angular' | ||
description: | | ||
Action that takes a built artifact, injects metadata, zips it up, uploads | ||
it to the current GitHub action workflow. | ||
Following best-practices from: | ||
https://securitylab.github.com/research/github-actions-preventing-pwn-requests | ||
# NOTE: All inputs here are considered unsafe since this action is expected | ||
# to run in workflows from forked builds (allowing for arbitrary changes). | ||
inputs: | ||
workflow-artifact-name: | ||
required: true | ||
description: | | ||
Name of the artifact that should be deployed. A workflow may contain | ||
multiple artifacts but only a single one can be picked for deployment. | ||
pull-number: | ||
required: true | ||
description: Pull request for which the artifact is built for. | ||
|
||
artifact-build-revision: | ||
required: true | ||
description: | | ||
A unique identifier describing the revision of the artifact. This is | ||
usually the Git SHA for which the artifact has been built. | ||
deploy-directory: | ||
required: true | ||
description: | | ||
Project-relative path to the directory contents that should be deployed. | ||
This is usually the distribution directory, like `dist/my-app/`. | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Injecting artifact metadata | ||
shell: bash | ||
run: | | ||
node ${{github.action_path}}/inject-artifact-metadata.js \ | ||
'${{inputs.deploy-directory}}' \ | ||
'${{inputs.pull-number}}' \ | ||
'${{inputs.artifact-build-revision}}' | ||
- uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 # renovate: tag=v2.0.0 | ||
with: | ||
name: '${{inputs.workflow-artifact-name}}' | ||
path: '${{inputs.deploy-directory}}' |
34 changes: 34 additions & 0 deletions
34
github-actions/deploy-previews/pack-and-upload-artifact/inject-artifact-metadata.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
|
||
import {createRequire as __cjsCompatRequire} from 'module'; | ||
const require = __cjsCompatRequire(import.meta.url); | ||
|
||
|
||
// | ||
import path from "path"; | ||
import fs from "fs"; | ||
|
||
// | ||
var artifactMetadata = { | ||
"pull-number": "./__metadata__pull_number.txt", | ||
"build-revision": "./__metadata__build_revision.txt" | ||
}; | ||
|
||
// | ||
async function main() { | ||
const [deployDirPath, prNumber, buildRevision] = process.argv.slice(2); | ||
await fs.promises.writeFile(path.join(deployDirPath, artifactMetadata["pull-number"]), prNumber); | ||
await fs.promises.writeFile(path.join(deployDirPath, artifactMetadata["build-revision"]), buildRevision); | ||
} | ||
try { | ||
await main(); | ||
} catch (e) { | ||
console.error(e); | ||
process.exit(1); | ||
} | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ |
12 changes: 12 additions & 0 deletions
12
github-actions/deploy-previews/pack-and-upload-artifact/lib/BUILD.bazel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
load("//tools:defaults.bzl", "ts_library") | ||
|
||
package(default_visibility = ["//github-actions/deploy-previews:__subpackages__"]) | ||
|
||
ts_library( | ||
name = "inject_artifact_metadata_lib", | ||
srcs = ["inject-artifact-metadata.ts"], | ||
deps = [ | ||
"//github-actions/deploy-previews:constants_lib", | ||
"@npm//@types/node", | ||
], | ||
) |
38 changes: 38 additions & 0 deletions
38
github-actions/deploy-previews/pack-and-upload-artifact/lib/inject-artifact-metadata.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* @license | ||
* Copyright Google LLC All Rights Reserved. | ||
* | ||
* Use of this source code is governed by an MIT-style license that can be | ||
* found in the LICENSE file at https://angular.io/license | ||
*/ | ||
|
||
/** | ||
* Injects metadata information into the given unpacked artifact. An artifact | ||
* is expected to contain metadata such as the pull request it was built for. | ||
* | ||
* The deploy job later will extract this information when it fetches the artifact. | ||
* | ||
* See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow. | ||
*/ | ||
|
||
import path from 'path'; | ||
import fs from 'fs'; | ||
|
||
import {artifactMetadata} from '../../constants.js'; | ||
|
||
async function main() { | ||
const [deployDirPath, prNumber, buildRevision] = process.argv.slice(2); | ||
|
||
await fs.promises.writeFile(path.join(deployDirPath, artifactMetadata['pull-number']), prNumber); | ||
await fs.promises.writeFile( | ||
path.join(deployDirPath, artifactMetadata['build-revision']), | ||
buildRevision, | ||
); | ||
} | ||
|
||
try { | ||
await main(); | ||
} catch (e) { | ||
console.error(e); | ||
process.exit(1); | ||
} |
19 changes: 19 additions & 0 deletions
19
github-actions/deploy-previews/upload-artifacts-to-firebase/BUILD.bazel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
load("//tools:defaults.bzl", "esbuild_checked_in") | ||
|
||
esbuild_checked_in( | ||
name = "fetch-workflow-artifact", | ||
entry_point = "//github-actions/deploy-previews/upload-artifacts-to-firebase/lib:fetch-workflow-artifact.ts", | ||
target = "node16", | ||
deps = [ | ||
"//github-actions/deploy-previews/upload-artifacts-to-firebase/lib:fetch_workflow_artifact_lib", | ||
], | ||
) | ||
|
||
esbuild_checked_in( | ||
name = "extract-artifact-metadata", | ||
entry_point = "//github-actions/deploy-previews/upload-artifacts-to-firebase/lib:extract-artifact-metadata.ts", | ||
target = "node16", | ||
deps = [ | ||
"//github-actions/deploy-previews/upload-artifacts-to-firebase/lib:extract_artifact_metadata_lib", | ||
], | ||
) |
87 changes: 87 additions & 0 deletions
87
github-actions/deploy-previews/upload-artifacts-to-firebase/action.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
name: Upload Artifacts to Firebase previews | ||
author: 'Angular' | ||
description: | | ||
Action that downloads a named artifact from a GitHub workflow and uploads | ||
it to a Firebase preview channel. The deployment to Firebase happens through | ||
a separate upload artifact workflow to avoid executing build processes in | ||
privileged environments. | ||
Following best-practices from: | ||
https://securitylab.github.com/research/github-actions-preventing-pwn-requests | ||
# NOTE: There are two categories of input data to this action: | ||
# | ||
# - TRUSTED: Values for such inputs should not be changeable by third-parties. | ||
# This is information usually hard-coded in the privileged job running from `main`. | ||
# | ||
# - RISK: These inputs are considered unsafe and values may be abused by third-parties. | ||
# This is usually information coming directly from the build job portion. | ||
inputs: | ||
github-token: | ||
required: true | ||
description: | | ||
TRUSTED: GitHub Token used for creating the commit statuses. | ||
workflow-artifact-name: | ||
required: true | ||
description: | | ||
TRUSTED: Name of the artifact that should be deployed. A workflow may contain | ||
multiple artifacts but only a single one can be picked for deployment. | ||
firebase-config-dir: | ||
default: './' | ||
description: | | ||
TRUSTED: Project-relative path to the directory containing the `firebase.json` file. | ||
firebase-public-dir: | ||
required: true | ||
description: | | ||
TRUSTED: Project-relative path to the directory where artifacts should be put into. | ||
firebase-project-id: | ||
required: true | ||
description: | | ||
TRUSTED: ID of the Firebase project used for deployment. | ||
firebase-service-key: | ||
required: true | ||
description: | | ||
TRUSTED: Contents of a Firebase service key authorizing the deployment. | ||
runs: | ||
using: composite | ||
steps: | ||
- name: 'Download artifact from build job' | ||
shell: bash | ||
run: | | ||
node ${{github.action_path}}/fetch-workflow-artifact.js \ | ||
'${{github.event.workflow_run.id}}' '${{inputs.workflow-artifact-name}}' > unsafe-artifact.zip" | ||
env: | ||
GITHUB_TOKEN: '${{inputs.github-token}}' | ||
|
||
# RISK: The downloaded `unsafe-artifact` is of input category `RISK`. | ||
- name: Extracting workflow artifact into Firebase public directory. | ||
shell: bash | ||
run: | | ||
mkdir -p '${{inputs.firebase-public-dir}}' | ||
unzip unsafe-artifact.zip -d '${{inputs.firebase-public-dir}}' | ||
- name: Extracting artifact metadata | ||
id: artifact-info | ||
shell: bash | ||
run: node ${{github.action_path}}/extract-artifact-metadata.js '${{inputs.firebase-public-dir}}' | ||
|
||
- uses: FirebaseExtended/action-hosting-deploy@276388dd6c2cde23455b30293105cc866c22282d # renovate: tag=v0.0.0 | ||
id: deploy | ||
with: | ||
# Note: No token used here as the action otherwise may attempt to post a | ||
# comment. We use our own sticky non-spam comments below. | ||
repoToken: '' | ||
firebaseServiceAccount: '${{inputs.firebase-service-key}}' | ||
expires: 20d | ||
projectId: '${{inputs.firebase-project-id}}' | ||
entryPoint: '${{inputs.firebase-config-dir}' | ||
channelId: pr-${{steps.artifact-info.outputs.pull-number}}-${{steps.artifact-info.outputs.build-revision}} | ||
|
||
- uses: marocchino/sticky-pull-request-comment@39c5b5dc7717447d0cba270cd115037d32d28443 # renovate: tag=v2.0.0 | ||
with: | ||
message: | | ||
Deployed ${{inputs.workflow-artifact-name}} to: ${{steps.deploy.outputs.details_url}} | ||
number: ${{steps.artifact-info.outputs.pull-number}} |
Oops, something went wrong.