-
Notifications
You must be signed in to change notification settings - Fork 403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ci(github): migrate ci from circleci to github #1852
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start so far!
I think we should also leave the Circle CI stuff in place too so that we have 2 sets of CI running (because, why not 😉 ).
Some comments:
- I see quite a bit of repetition between these files, do github actions have a way of sharing steps, etc between multiple workflows (forgive my ignorance, and inexperience with GH actions if it shows).
- Is it possible to do the same as what we have in CircleCI, where the build happens, and then the tasks all happen mainly in parallel where they don't depend on each other?
@markwhitfeld there are reusable workflows, but it might be a bit more complex to read and maintain it for someone inexperienced with GH actions. I will try to make it as simple as possible, need to check if its possible to share step execution results between reusable workflows. This feature, |
@markwhitfeld please check my latest commit in this branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have left a few comments here, but we can chat about the details on a call 👍
Here are some great articles that have some awesome recommendations, and security guidances for Github Actions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! I have a question: could you leave comments to commands like find ~/.npmrc -exec shred -fuz {} +
? This would be obvious for reviewers on what this command is doing and will be easier to maintain it in the future, just because everyone will know what it's responsible for.
E.g. this would be great:
# This command is doing ..... `shred -fuz {}` is doing blah blah....
find ~/.npmrc -exec shred -fuz {} +
updated |
- name: Development release - publish development builds to all @ngxs packages | ||
run: | | ||
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc | ||
yarn publish:dev | ||
echo "Security: remove ~/.npmrc from the runner overwriting it with zeros several times." | ||
find ~/.npmrc -exec shred -fuz {} + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, we need to copy in the build artefacts before this step
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above - 016b129
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for this!
Just a few more tweaks...
I'm still battling to get GitHub to allow this to run. Maybe you can experiment and test this in your own clean repo with some spoofed data and scripts. Then you are not blocked with not being able to run it in the meantime. What do you think?
.github/workflows/_setup.yml
Outdated
~/.cache | ||
./node_modules | ||
./@ngxs | ||
key: ${{ runner.os }}-node-${{ matrix.node-version }}-yarn-${{ hashFiles('**/yarn.lock') }}-branch-${{ steps.get-variables.outputs.shortref }}-workspace-${{ steps.get-variables.outputs.commitsha }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the NODE_VERSION variable here and below too, still referencing the matrix strategy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@markwhitfeld fixed
chmod +x /tmp/cc-test-reporter | ||
/tmp/cc-test-reporter after-build --coverage-input-type lcov --exit-code 0 | ||
env: | ||
CC_TEST_REPORTER_ID: 3f4c9a9d57ded045e0f9ab5d23e5bbcbf709bb85637bea555f1233e72134b818 # TODO: better store it in the repository secrets. Name the variable: CC_TEST_REPORTER_ID. Then delete this line and uncomment the next one |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, can we move this to secrets
.github/workflows/_setup.yml
Outdated
path: | | ||
~/.cache | ||
./node_modules | ||
./@ngxs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just wondering if putting this in the cache is potentially a security concern.
Trying to think if this can be exploited in any way by someone writing malicious code to the cache between our build and deploy.
The next alternative I think about is using the store and repetitive artefact action, but is that safer?
Possibly we should actually run the build again in the publish job to be safest.
@arturovt & @rfprod what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@markwhitfeld I think that in this particular case, the likelihood that something will go wrong with the artifacts is extremely small.
Here's why:
- when the workflow (trunk or release) is kicked off, the first job is
*-build
(trunk-build
orrelease-build
) <-*-build
jobs refreshworkspace-cache
by rebuilding all packages and saving it to the cache. - Then several more jobs are executed:
*-test
,*-integration-test
,*-bundlesize
. - Then the
*-publish
job is executed. Thepublish
job uses build artifacts that were generated by the*-build
job (see point 1 of this list).
A possible attack surface is in between of build
and publish
, it's point 2 in the list above.
The attacker should be very persistent and determined to mess up the publish step.
If we assume that the workspace artifacts (including the build artifacts) are corrupted before *-build
, they will be fixed after the *-build
job completion.
I think, with the same probability someone could tap into the runner and corrupt the build artifacts. Of course there is a probability of this, but it tends to zero.
If you want an additional layer of protection to be sure that the build artifacts were not changed after caching and before publishing, we can hash the content of each directory with the build artifacts and save hashing results as part of the workspace-cache
. The _check-build-artifacts.yml
workflow can be configured to verify hashes in addition to ensuring that the directories exist.
PS: In addition to hashing, we can encrypt the build artifacts before saving it to cache. This will increase complexity, but make it much harder for build artifacts to become corrupted, even if they are stored externally. The procedure is not be very complex, and it can be fully automated. The process is like:
- before save:
archive artifacts, e.g. tar.gz
->encrypt (gpg, passphrase)
->hash encrypted archives
- before use:
verify hashes of the encrypted archives
->decrypt (gpg, passphrase)
->unarchive artifacts
The gpg passphrase can be stored in the repository secrets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your very well-thought-out response.
I think that it is good to bear this in mind, but I don't think it is essential right now.
I think that the simplest approach is to keep what we have here, using the cache to make the built files available to the next job, and then in the publish step, we could just build it again. It is repeating the work, but everything preceding the publish leveraged the built files as part of the validation leading up to the publish. It is OK if the publish repeats a number of steps to be safer because it is on the tail end of the workflow and will not slow the PR workflow down.
@rfprod after reading this article: https://github.blog/2021-11-29-github-actions-reusable-workflows-is-generally-available/ |
@markwhitfeld As I mentioned during our call, I haven't used reusable workflows like this before. :) I'll try if this approach actually works, maybe tomorrow. PS: check my latest commits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great.
Now just to see it running!!?!
Hopefully this approved review opens that option...
PS. Team, please wait for me to merge once we have potentially iterated a few times with seeing it in action.
- [x] reimplement circleci workflows using github actions ci;
- [x] add a cleanup command that removes .npmrc after publishing packages;
- [x] clean up workflows, add comments to justify suggestions; - [x] implement a reusable workflow that might be used later, add explanatory comments;
Co-authored-by: Mark Whitfeld <[email protected]>
Co-authored-by: Mark Whitfeld <[email protected]>
- [x] use a reusable workflow to setup all jobs; - [x] use a matrix strategy to parallelize scripts execution;
- [x] add a reusable workflow to check for build artifacts;
@markwhitfeld |
- [x] all actions must required build so that cache is correct;
@markwhitfeld cache is immutable. Check my latest changes. |
It is looking great. So nice to see it running! |
@markwhitfeld faster subsequent pipeline runs are the advantage. For example, if you modify source code of only one ngxs package, jest will process other libraries faster if there is cache of the previous test runs.
I'll add artifacts to the workflows later today. Will post an update here after. |
- [x] add two composite actions to upload/download integration test artifacts;
@markwhitfeld all jobs green. Pipeline run https://github.com/rfprod/store/actions/runs/2491727586 |
with: | ||
fetch-depth: 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a good default. Is there a reason why this is not done in the other workflows for the checkout step?
If they can all be the same, then this could actually be moved into the setup
composite action.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@markwhitfeld fetch-depth: 0
stands for all history for all branches and tags. It should be a bit slower and it pulls much more data than needed for other workflows than those that validate pull requests. From my experience with common repos and monorepos, it is generally not needed to pull all git history in the trunk
or release
workflows, because all tests that might require full commit history of all branches and tags (e.g. validate commit messages using commitlint) were done earlier during the corresponding PR validation.
If you think the default fetch-depth: 0
makes sense, so be it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Makes sense. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@markwhitfeld one more thing about the actions/checkout
action.
Sources should be checked out prior to any steps that use composite actions like ./github/actions/...
, because relative references requires already checkout out sources.
If you want to wrap the step that check out sources as a separate composite action, the only way to reference this composite action that will work, if I understand correctly, is ngxs/store/.github/actions/...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, hahaha. Yes, that makes total sense!
* ci(github): migrate ci from circleci to github - [x] reimplement circleci workflows using github actions ci; * ci(cleanup): remove .npmrc after publishing packages - [x] add a cleanup command that removes .npmrc after publishing packages; * ci(github): revise github actions ci workflows - [x] clean up workflows, add comments to justify suggestions; - [x] implement a reusable workflow that might be used later, add explanatory comments; * Update .github/workflows/get-variables.yml Co-authored-by: Mark Whitfeld <[email protected]> * Update .github/workflows/pr-validation.yml Co-authored-by: Mark Whitfeld <[email protected]> * ci(premerge): upload premerge unit test coverage results to code climate * ci(dry): setup jobs with a reusable workflow, use matrix for scripts - [x] use a reusable workflow to setup all jobs; - [x] use a matrix strategy to parallelize scripts execution; * ci(logging): echo explanation of the 'find ... shred ...' command * ci(artifacts): check build artifacts workflow - [x] add a reusable workflow to check for build artifacts; * ci(setup): fix setup workflow - get node version from inputs * ci(artifacts): save app/integrations dists to workspace cache * ci(actions): convert reusable workflows to composite actions * ci(actions): fix composite actions * ci(actions): update comments in action configs * ci(docs): fix comments in composite actions * ci(syntax): fix yaml syntax errors * ci(checkout): checkout sources before calling the setup action * ci(inputs): fix the setup action inputs * ci(syntax): fix the setup action syntax * ci(test): test:types needs *-build, move it to integration-test * ci(cache): fix workspace cache paths * ci(cache): exclude node_modules in the integrations dir from cache * ci(cache): fix workspace cache, remove unneeded code * ci(cache): fix workspace cache - [x] all actions must required build so that cache is correct; * ci(actions): add composite actions to upload/download artifacts - [x] add two composite actions to upload/download integration test artifacts; * fix: bundlesize step order (release & trunk) Co-authored-by: Mark Whitfeld <[email protected]>
echo
explanation of thefind ... shred ...
command;@ngxs
build artifacts, add a reusable workflow to check for build artifacts;app/integrations
dists (needed forbundlesize
job);PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Implementation of CI workflows using GitHub Actions CI.
What is the current behavior?
CircleCI does not always work as expected.
Issue Number: N/A
What is the new behavior?
CircleCI workflows were reimplementd using GitHub Actions CI.
Does this PR introduce a breaking change?
Other information
There're some TODOs that should be reviewed and addressed in the future.
GitHub Actions CI workflow steps that publish packages to NPM are commented out.
Before uncommenting the GitHub Actions CI workflow steps that publish packages to NPM, the new workflows must be tested first.