docs(docs-infra): update preview server docs to account for recent changes (#25671)
Mostly (but not exclusively) a follow-up to #23576. PR Close #25671
This commit is contained in:
parent
e42bd012f9
commit
d8d276c245
|
@ -5,4 +5,5 @@ TODO (gkalpak): Add docs. Mention:
|
||||||
- Testing on CI.
|
- Testing on CI.
|
||||||
Relevant files: `scripts/ci/test-aio.sh`, `aio/aio-builds-setup/scripts/test.sh`
|
Relevant files: `scripts/ci/test-aio.sh`, `aio/aio-builds-setup/scripts/test.sh`
|
||||||
- Deploying from CI.
|
- Deploying from CI.
|
||||||
Relevant files: `scripts/ci/deploy.sh`, `aio/scripts/deploy-to-firebase.sh`
|
Relevant files: `.circleci/config.yml`, `scripts/ci/deploy.sh`, `aio/scripts/build-artifacts.sh`,
|
||||||
|
`aio/scripts/deploy-to-firebase.sh`
|
||||||
|
|
|
@ -34,34 +34,31 @@ container:
|
||||||
|
|
||||||
|
|
||||||
### On CI (CircleCI)
|
### On CI (CircleCI)
|
||||||
- Build job completes successfully.
|
- The CI script builds the angular.io project.
|
||||||
- The CI script checks whether the build job was initiated by a PR against the angular/angular
|
|
||||||
master branch.
|
|
||||||
- The CI script checks whether the PR has touched any files that might affect the angular.io app
|
|
||||||
(currently the `aio/` or `packages/` directories, ignoring spec files).
|
|
||||||
- The CI script gzips and stores the build artifacts in the CI infrastructure.
|
- The CI script gzips and stores the build artifacts in the CI infrastructure.
|
||||||
- When the build completes CircleCI triggers a webhook on the preview-server.
|
- When the build completes, CircleCI triggers a webhook on the preview-server.
|
||||||
|
|
||||||
More info on how to set things up on CI can be found [here](misc--integrate-with-ci.md).
|
More info on how to set things up on CI can be found [here](misc--integrate-with-ci.md).
|
||||||
|
|
||||||
|
|
||||||
### Hosting build artifacts
|
### Hosting build artifacts
|
||||||
|
|
||||||
- nginx receives the webhook trigger and passes it through to the preview server.
|
- nginx receives the webhook trigger and passes it through to the preview server.
|
||||||
|
- The preview-server runs several preliminary checks to determine whether the request is valid and
|
||||||
|
whether the corresponding PR can have a (public or non-public) preview (more details can be found
|
||||||
|
[here](overview--security-model.md)).
|
||||||
- The preview-server makes a request to CircleCI for the URL of the AIO build artifacts.
|
- The preview-server makes a request to CircleCI for the URL of the AIO build artifacts.
|
||||||
- The preview-server makes a request to this URL to receive the artifact - failing if the size
|
- The preview-server makes a request to this URL to receive the artifact - failing if the size
|
||||||
exceeds the specified max file size - and stores it in a temporary location.
|
exceeds the specified max file size - and stores it in a temporary location.
|
||||||
- The preview-server runs several checks to determine whether the request should be accepted and
|
- The preview-server runs more checks to determine whether the preview should be publicly accessible
|
||||||
whether it should be publicly accessible or stored for later verification (more details can be
|
or stored for later verification (more details can be found [here](overview--security-model.md)).
|
||||||
found [here](overview--security-model.md)).
|
|
||||||
- The preview-server changes the "visibility" of the associated PR, if necessary. For example, if
|
- The preview-server changes the "visibility" of the associated PR, if necessary. For example, if
|
||||||
builds for the same PR had been previously deployed as non-public and the current build has been
|
builds for the same PR had been previously deployed as non-public and the current build has been
|
||||||
automatically verified, all previous builds are made public as well.
|
automatically verified, all previous builds are made public as well.
|
||||||
If the PR transitions from "non-public" to "public", the preview-server posts a comment on the
|
If the PR transitions from "non-public" to "public", the preview-server posts a comment on the
|
||||||
corresponding PR on GitHub mentioning the SHAs and the links where the previews can be found.
|
corresponding PR on GitHub mentioning the SHAs and the links where the previews can be found.
|
||||||
- The preview-server verifies that it is not trying to overwrite an existing build.
|
- The preview-server verifies that it is not trying to overwrite an existing build.
|
||||||
- The preview-server deploys the artifacts to a sub-directory named after the PR number and the first
|
- The preview-server deploys the artifacts to a sub-directory named after the PR number and the
|
||||||
few characters of the SHA: `<PR>/<SHA>/`
|
first few characters of the SHA: `<PR>/<SHA>/`
|
||||||
(Non-publicly accessible PRs will be stored in a different location, but again derived from the PR
|
(Non-publicly accessible PRs will be stored in a different location, but again derived from the PR
|
||||||
number and SHA.)
|
number and SHA.)
|
||||||
- If the PR is publicly accessible, the preview-server posts a comment on the corresponding PR on
|
- If the PR is publicly accessible, the preview-server posts a comment on the corresponding PR on
|
||||||
|
@ -101,8 +98,8 @@ More info on the possible HTTP status codes and their meaning can be found
|
||||||
|
|
||||||
### Removing obsolete artifacts
|
### Removing obsolete artifacts
|
||||||
In order to avoid flooding the disk with unnecessary build artifacts, there is a cronjob that runs a
|
In order to avoid flooding the disk with unnecessary build artifacts, there is a cronjob that runs a
|
||||||
clean-up tasks once a day. The task retrieves all open PRs from GitHub and removes all directories
|
clean-up task once a day. The task retrieves all open PRs from GitHub and removes all directories
|
||||||
that do not correspond with an open PR.
|
that do not correspond to an open PR.
|
||||||
|
|
||||||
|
|
||||||
### Health-check
|
### Health-check
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# Overview - HTTP Status Codes
|
# Overview - HTTP Status Codes
|
||||||
|
|
||||||
|
|
||||||
This is a list of all the possible HTTP status codes returned by the nginx and preview servers, along
|
This is a list of all the possible HTTP status codes returned by the nginx and preview servers,
|
||||||
with a brief explanation of what they mean:
|
along with a brief explanation of what they mean:
|
||||||
|
|
||||||
|
|
||||||
## `http://*.ngbuilds.io/*`
|
## `http://*.ngbuilds.io/*`
|
||||||
|
|
|
@ -11,8 +11,8 @@ part of the CI process and serving them publicly.
|
||||||
|
|
||||||
## Security objectives
|
## Security objectives
|
||||||
|
|
||||||
- **Prevent hosting arbitrary content to on servers.**
|
- **Prevent hosting arbitrary content on our servers.**
|
||||||
Since there is no restriction on who can submit a PR, we cannot allow arbitrary untrusted PRs'
|
Since there is no restriction on who can submit a PR, we cannot allow arbitrary, untrusted PRs'
|
||||||
build artifacts to be hosted.
|
build artifacts to be hosted.
|
||||||
|
|
||||||
- **Prevent overwriting other people's hosted build artifacts.**
|
- **Prevent overwriting other people's hosted build artifacts.**
|
||||||
|
@ -40,40 +40,49 @@ part of the CI process and serving them publicly.
|
||||||
### In a nutshell
|
### In a nutshell
|
||||||
The implemented approach can be broken up to the following sub-tasks:
|
The implemented approach can be broken up to the following sub-tasks:
|
||||||
|
|
||||||
0. Receive notification from CircleCI of a completed build.
|
1. Receive notification from CircleCI of a completed build.
|
||||||
1. Verify that the build is valid and download the artifact.
|
2. Verify that the build is valid and can have a preview.
|
||||||
2. Fetch the PR's metadata, including author and labels.
|
3. Download the build artifact.
|
||||||
3. Check whether the PR can be automatically verified as "trusted" (based on its author or labels).
|
4. Fetch the PR's metadata, including author and labels.
|
||||||
4. If necessary, update the corresponding PR's verification status.
|
5. Check whether the PR can be automatically verified as "trusted" (based on its author or labels).
|
||||||
5. Deploy the artifacts to the corresponding PR's directory.
|
6. If necessary, update the corresponding PR's verification status.
|
||||||
6. Prevent overwriting previously deployed artifacts (which ensures that the guarantees established
|
7. Deploy the artifacts to the corresponding PR's directory.
|
||||||
|
8. Prevent overwriting previously deployed artifacts (which ensures that the guarantees established
|
||||||
during deployment will remain valid until the artifacts are removed).
|
during deployment will remain valid until the artifacts are removed).
|
||||||
7. Prevent hosted preview files from accessing anything outside their directory.
|
9. Prevent hosted preview files from accessing anything outside their directory.
|
||||||
|
|
||||||
|
|
||||||
### Implementation details
|
### Implementation details
|
||||||
This section describes how each of the aforementioned sub-tasks is accomplished:
|
This section describes how each of the aforementioned sub-tasks is accomplished:
|
||||||
|
|
||||||
0. **Receive notification from CircleCI of a completed build**
|
1. **Receive notification from CircleCI of a completed build**
|
||||||
|
|
||||||
CircleCI is configured to trigger a webhook on our preview-server whenever a build completes.
|
CircleCI is configured to trigger a webhook on our preview-server whenever a build completes.
|
||||||
The payload contains the number of the build that completed.
|
The payload contains the number of the build that completed.
|
||||||
|
|
||||||
1. **Verify that the build is valid and download the artifact.**
|
2. **Verify that the build is valid and can have a preview.**
|
||||||
|
|
||||||
We cannot trust that the data in the webhook trigger is authentic, so we only extract the build
|
We cannot trust that the data in the webhook trigger is authentic, so we only extract the build
|
||||||
number and then run a direct query against the CircleCI API to get hold of the real data for
|
number and then run a direct query against the CircleCI API to get hold of the real data for
|
||||||
the given build number.
|
the given build number.
|
||||||
|
|
||||||
If the build was not successful then we ignore this trigger. Otherwise we check that the
|
We perform a number of preliminary checks:
|
||||||
associated github organisation and repository are what we expect (e.g. angular/angular).
|
- Was the webhook triggered by the designated CircleCI job (currently `aio_preview`)?
|
||||||
|
- Was the build successful?
|
||||||
|
- Are the associated GitHub organisation and repository what we expect (e.g. `angular/angular`)?
|
||||||
|
- Has the PR touched any files that might affect the angular.io app (currently the `aio/` or
|
||||||
|
`packages/` directories, ignoring spec files)?
|
||||||
|
|
||||||
Next we make another call to the CircleCI API to get a list of the URLS for artifacts of that
|
If any of the preliminary checks fails, the process is aborted and not preview is generated.
|
||||||
|
|
||||||
|
3. **Download the build artifact.**
|
||||||
|
|
||||||
|
Next we make another call to the CircleCI API to get a list of the URLs for artifacts of that
|
||||||
build. If there is one that matches the configured artifact path, we download the contents of the
|
build. If there is one that matches the configured artifact path, we download the contents of the
|
||||||
build artifact and store it in a local folder. This download has a maximum size limit to prevent
|
build artifact and store it in a local folder. This download has a maximum size limit to prevent
|
||||||
PRs from producing artifacts that are so large they would cause the preview server to crash.
|
PRs from producing artifacts that are so large they would cause the preview server to crash.
|
||||||
|
|
||||||
2. **Fetch the PR's metadata, including author and labels**.
|
4. **Fetch the PR's metadata, including author and labels**.
|
||||||
|
|
||||||
Once we have securely downloaded the artifact for a build, we retrieve the PR's metadata -
|
Once we have securely downloaded the artifact for a build, we retrieve the PR's metadata -
|
||||||
including the author's username and the labels - using the
|
including the author's username and the labels - using the
|
||||||
|
@ -81,7 +90,7 @@ This section describes how each of the aforementioned sub-tasks is accomplished:
|
||||||
To avoid rate-limit restrictions, we use a Personal Access Token (issued by
|
To avoid rate-limit restrictions, we use a Personal Access Token (issued by
|
||||||
[@mary-poppins](https://github.com/mary-poppins)).
|
[@mary-poppins](https://github.com/mary-poppins)).
|
||||||
|
|
||||||
3. **Check whether the PR can be automatically verified as "trusted"**.
|
5. **Check whether the PR can be automatically verified as "trusted"**.
|
||||||
|
|
||||||
"Trusted" means that we are confident that the build artifacts are suitable for being deployed
|
"Trusted" means that we are confident that the build artifacts are suitable for being deployed
|
||||||
and publicly accessible on the preview server. There are two ways to check that:
|
and publicly accessible on the preview server. There are two ways to check that:
|
||||||
|
@ -93,31 +102,32 @@ This section describes how each of the aforementioned sub-tasks is accomplished:
|
||||||
`read:org` scope issued by a user that can "see" the specified GitHub organization.
|
`read:org` scope issued by a user that can "see" the specified GitHub organization.
|
||||||
Here too, we use the token by @mary-poppins.
|
Here too, we use the token by @mary-poppins.
|
||||||
|
|
||||||
4. **If necessary update the corresponding PR's verification status**.
|
6. **If necessary update the corresponding PR's verification status**.
|
||||||
|
|
||||||
Once we have determined whether the PR is considered "trusted", we update its "visibility" (i.e.
|
Once we have determined whether the PR is considered "trusted", we update its "visibility" (i.e.
|
||||||
whether it is publicly accessible or not), based on the new verification status. For example, if
|
whether it is publicly accessible or not), based on the new verification status. For example, if
|
||||||
a PR was initially considered "not trusted" but the check triggered by a new build determined
|
a PR was initially considered "not trusted" but the check triggered by a new build determined
|
||||||
otherwise, the PR (and all the previously hosted previews) are made public. It works the same
|
otherwise, the PR (and all the previously downloaded previews) are made public. It works the same
|
||||||
way if a PR has gone from "trusted" to "not trusted".
|
way if a PR has gone from "trusted" to "not trusted".
|
||||||
|
|
||||||
5. **Deploy the artifacts to the corresponding PR's directory.**
|
7. **Deploy the artifacts to the corresponding PR's directory.**
|
||||||
|
|
||||||
With the preceding steps, we have verified that the build artifacts are valid.
|
With the preceding steps, we have verified that the build artifacts are valid. Additionally, we
|
||||||
Additionally, we have determined whether the PR can be trusted to have its previews
|
have determined whether the PR can be trusted to have its previews publicly accessible or whether
|
||||||
publicly accessible or whether further verification is necessary. The artifacts will be stored to
|
further verification is necessary.
|
||||||
the PR's directory, but will not be publicly accessible unless the PR has been verified.
|
|
||||||
Essentially, as long as sub-tasks 1, 2 and 3 can be securely accomplished, it is possible to
|
|
||||||
"project" the trust we have in a team's members through the PR to the build artifacts.
|
|
||||||
|
|
||||||
6. **Prevent overwriting previously deployed artifacts**.
|
The artifacts will be stored to the PR's directory, but will not be publicly accessible unless
|
||||||
|
the PR has been verified. Essentially, as long as sub-tasks 2, 3, 4 and 5 can be securely
|
||||||
|
accomplished, it is possible to "project" the trust we have in a team's members through the PR to
|
||||||
|
the build artifacts.
|
||||||
|
|
||||||
|
8. **Prevent overwriting previously deployed artifacts**.
|
||||||
|
|
||||||
In order to enforce this restriction (and ensure that the deployed artifacts' validity is
|
In order to enforce this restriction (and ensure that the deployed artifacts' validity is
|
||||||
preserved throughout their "lifetime"), the server that handles the artifacts (currently a Node.js
|
preserved throughout their "lifetime"), the server that handles the artifacts (currently a Node.js Express server) rejects builds that have already been handled.
|
||||||
Express server) rejects builds that have already been handled.
|
|
||||||
_Note: A PR can contain multiple builds; one for each SHA that was built on CircleCI._
|
_Note: A PR can contain multiple builds; one for each SHA that was built on CircleCI._
|
||||||
|
|
||||||
7. **Prevent hosted preview files from accessing anything outside their directory.**
|
9. **Prevent hosted preview files from accessing anything outside their directory.**
|
||||||
|
|
||||||
Nginx (which is used to serve the hosted preview) has been configured to not follow symlinks
|
Nginx (which is used to serve the hosted preview) has been configured to not follow symlinks
|
||||||
outside of the directory where the preview files are stored.
|
outside of the directory where the preview files are stored.
|
||||||
|
@ -130,10 +140,10 @@ This section describes how each of the aforementioned sub-tasks is accomplished:
|
||||||
This means that any secret access keys need only be stored on the preview-server and not on any of
|
This means that any secret access keys need only be stored on the preview-server and not on any of
|
||||||
the CI build infrastructure (e.g. CircleCI).
|
the CI build infrastructure (e.g. CircleCI).
|
||||||
|
|
||||||
- Each trusted PR author has full control over the content that is hosted as a preview for their PRs.
|
- Each trusted PR author has full control over the content that is hosted as a preview for their
|
||||||
Part of the security model relies on the trustworthiness of these authors.
|
PRs. Part of the security model relies on the trustworthiness of these authors.
|
||||||
|
|
||||||
- Adding the specified label on a PR to mark it as trusted, gives the author full control over
|
- Adding the specified label on a PR to mark it as trusted, gives the author full control over the
|
||||||
the content that is hosted for the specific PR preview (e.g. by pushing more commits to it).
|
content that is hosted for the specific PR preview (e.g. by pushing more commits to it). The user
|
||||||
The user adding the label is responsible for ensuring that this control is not abused and that
|
adding the label is responsible for ensuring that this control is not abused and that the PR is
|
||||||
the PR is either closed (one way of another) or the access is revoked.
|
either closed (one way of another) or the access is revoked.
|
||||||
|
|
|
@ -8,7 +8,7 @@ Necessary secrets:
|
||||||
1. `GITHUB_TOKEN`
|
1. `GITHUB_TOKEN`
|
||||||
- Used for:
|
- Used for:
|
||||||
- Retrieving open PRs without rate-limiting.
|
- Retrieving open PRs without rate-limiting.
|
||||||
- Retrieving PR author.
|
- Retrieving PR info, such as author, labels, changed files.
|
||||||
- Retrieving members of the trusted GitHub teams.
|
- Retrieving members of the trusted GitHub teams.
|
||||||
- Posting comments with preview links on PRs.
|
- Posting comments with preview links on PRs.
|
||||||
|
|
||||||
|
@ -25,8 +25,9 @@ Necessary secrets:
|
||||||
- Generate new token with the `public_repo` scope.
|
- Generate new token with the `public_repo` scope.
|
||||||
|
|
||||||
2. `CIRCLE_CI_TOKEN`
|
2. `CIRCLE_CI_TOKEN`
|
||||||
- Visit https://circleci.com/gh/angular/angular/edit#api
|
- Visit https://circleci.com/gh/angular/angular/edit#api.
|
||||||
- Create an API token with `Build Artifacts` scope
|
- Create an API token with `Build Artifacts` scope.
|
||||||
|
|
||||||
|
|
||||||
## Save secrets on the VM
|
## Save secrets on the VM
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue