-
Notifications
You must be signed in to change notification settings - Fork 32
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
feat: macos signing and notarization #367
Changes from all commits
cd78bdf
8e11abe
f3c456d
3e9a8e2
796aaae
ed656e5
7d222b5
f115f93
9acff7e
87c0b11
9544654
c239cfb
ef7843a
835df84
1c9b839
3a3e3d8
84af7e2
79f20c2
2d131bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,35 +7,130 @@ on: | |
pull_request: | ||
branches: | ||
- master | ||
workflow_dispatch: | ||
inputs: | ||
dist_root: | ||
description: 'DIST_ROOT' | ||
required: true | ||
default: '/ipns/dist.ipfs.io' | ||
|
||
env: | ||
DIST_ROOT: ${{ github.event.inputs.custom_dist_root || '/ipns/dist.ipfs.io' }} # content root used for calculating diff to build | ||
GO_IPFS_VER: 'v0.9.1' # go-ipfs daemon used for chunking and applying diff | ||
CLUSTER_CTL_VER: 'v0.14.0' # ipfs-cluster-ctl used for pinning | ||
|
||
jobs: | ||
build: | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v2-beta | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '14' | ||
- uses: actions/setup-go@v2 | ||
- name: Setup IPFS | ||
run: ./scripts/ci/setup-ipfs.sh | ||
env: | ||
CLUSTER_USER: ${{ secrets.CLUSTER_USER }} | ||
CLUSTER_PASSWORD: ${{ secrets.CLUSTER_PASSWORD }} | ||
timeout-minutes: 5 | ||
- name: Build any new ./releases | ||
run: ./dockerized make all_dists | ||
- name: Inspect git status and contents of ./releases | ||
run: git status && ls -Rhl ./releases | ||
- name: Temporarily save ./releases artifacts | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
go-version: '1.16' | ||
- run: sudo snap install ipfs jq | ||
- run: ipfs init --profile server | ||
- run: ipfs daemon & | ||
- name: Wait for ipfs daemon | ||
run: npx wait-port http://127.0.0.1:8080/api/v0/version | ||
- name: Connect to ipfs cluster | ||
run: ipfs swarm connect /dnsaddr/cluster.ipfs.io | ||
- run: make publish | ||
# todo: add $(cat versions) to cluster (and wait) | ||
# todo: update dist dnslink if changed. | ||
|
||
lint: | ||
name: releases-unsigned-diff | ||
path: releases | ||
retention-days: 1 | ||
|
||
lint: | ||
runs-on: "ubuntu-latest" | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/setup-node@v2-beta | ||
- uses: actions/setup-node@v2 | ||
with: | ||
node-version: '14' | ||
- run: npm ci --no-audit --progress=false | ||
- run: npm run lint | ||
|
||
sign-macos: | ||
runs-on: "macos-latest" | ||
needs: build | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Retrieve unsigned artifacts | ||
uses: actions/download-artifact@v2 | ||
with: | ||
name: releases-unsigned-diff | ||
path: releases | ||
continue-on-error: true # skip if no releases | ||
- name: List ./releases before | ||
run: ls -Rhl ./releases || echo "No ./releases" | ||
- name: Install gon via HomeBrew for code signing and app notarization | ||
run: | | ||
brew tap mitchellh/gon | ||
brew install ipfs coreutils gawk gnu-sed jq mitchellh/gon/gon | ||
Comment on lines
+72
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ gon package is used by Terraform project, so multiple eyes are looking at this |
||
ipfs init --profile test # needed for calculating NEW_CID later | ||
- name: Import Keychain Certs | ||
uses: apple-actions/import-codesign-certs@253ddeeac23f2bdad1646faac5c8c2832e800071 # v1@2020-02-03 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ 👮♂️ I hardcoded specific revision because this is a third-party action and in theory someone could swap-out git tag and steal our signing keys. |
||
with: | ||
p12-file-base64: ${{ secrets.APPLE_CERTS_P12 }} | ||
p12-password: ${{ secrets.APPLE_CERTS_PASS }} | ||
- name: Verify identity used for signing | ||
run: security find-identity -v | ||
- name: Sign any new releases | ||
run: ./scripts/ci/sign-new-macos-releases.sh | ||
env: | ||
WORK_DIR: ${{ github.workspace }} | ||
AC_USERNAME: ${{ secrets.APPLE_AC_USERNAME }} # implicitly read from env by gon | ||
AC_PASSWORD: ${{ secrets.APPLE_AC_PASSWORD }} | ||
- name: List ./releases after | ||
run: ls -Rhl ./releases || echo "No ./releases" | ||
- name: Temporarily save notarized artifacts | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: releases-signed-macos-diff | ||
path: releases | ||
retention-days: 1 | ||
continue-on-error: true # skip if no releases | ||
|
||
persist: | ||
runs-on: "ubuntu-latest" | ||
needs: sign-macos | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Retrieve signed artifacts | ||
uses: actions/download-artifact@v2 | ||
continue-on-error: true # skip if no releases | ||
with: | ||
name: releases-signed-macos-diff | ||
path: releases | ||
- name: List ./releases | ||
run: ls -Rhl ./releases || echo "No ./releases" | ||
- name: Setup IPFS | ||
run: ./scripts/ci/setup-ipfs.sh | ||
env: | ||
CLUSTER_USER: ${{ secrets.CLUSTER_USER }} | ||
CLUSTER_PASSWORD: ${{ secrets.CLUSTER_PASSWORD }} | ||
timeout-minutes: 5 | ||
- run: ./dockerized make publish | ||
- run: git status | ||
- name: Read CID of updated DAG | ||
id: cid-reader | ||
run: echo "::set-output name=CID::$(tail -1 ./versions)" | ||
- name: Pin new website to ipfs-websites.collab.ipfscluster.io | ||
run: ./scripts/ci/pin-to-cluster.sh | ||
env: | ||
PIN_CID: ${{ steps.cid-reader.outputs.CID }} | ||
PIN_NAME: "https://github.com/ipfs/distributions/commits/${{ github.sha }}" | ||
PIN_ADD_EXTRA_ARGS: "" | ||
CLUSTER_USER: ${{ secrets.CLUSTER_USER }} | ||
CLUSTER_PASSWORD: ${{ secrets.CLUSTER_PASSWORD }} | ||
timeout-minutes: 60 | ||
- name: Update PR status with preview link | ||
run: ./scripts/ci/github-preview-link.sh | ||
env: | ||
CONTENT_PATH: "/ipfs/${{ steps.cid-reader.outputs.CID }}/" | ||
GIT_REVISION: ${{ github.sha }} | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,13 +20,17 @@ | |
- [Adding a new (go) distribution](#adding-a-new-go-distribution) | ||
- [Publishing](#publishing) | ||
- [Background](#background) | ||
- [Notes on reproducible builds](#notes-on-reproducible-builds) | ||
- [Contribute](#contribute) | ||
- [Want to hack on IPFS?](#want-to-hack-on-ipfs) | ||
- [License](#license) | ||
|
||
## Install | ||
|
||
Clone the repo and install the following dependencies via your favorite package manager: | ||
Clone the repo and use Docker via `./dockerized <cmd>` wrapper. | ||
|
||
If you don't want to run `./dockerized` build, install | ||
the following dependencies via your favorite package manager: | ||
|
||
* `go` | ||
* `npm` (v7.13.0+ with nodejs v16.2.0+) | ||
|
@@ -83,13 +87,20 @@ Run: | |
> ./dist.sh add-version <dist> <version> | ||
``` | ||
|
||
This will add the version to `dists/<dist>/versions`, set it as the current version in `dists/<dist>/current`, and build it. | ||
This will add the version to `dists/<dist>/versions`, set it as the current version in `dists/<dist>/current`, and build it locally. | ||
|
||
Example: | ||
```sh | ||
> ./dist.sh add-version fs-repo-99-to-100 v1.0.1 | ||
``` | ||
|
||
To produce a signed, **official build** for use in DNSLink at `dist.ipfs.io`: | ||
|
||
1. Run `./dist.sh add-version` locally. | ||
2. Commit created changes to `dists/<dist>` and open a PR against `ipfs/distributions`. | ||
3. Wait for Github Action to finish PR build. It runs `./dockerized` build, then signs macOS binaries and spits out updated root CID at the end. | ||
4. If everything looks good, write down the CID from the preview link on the PR, and update the DNSlink at `dist.ipfs.io`. | ||
Comment on lines
+97
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ I believe this is the TLDR of this entire PR :) |
||
|
||
### Adding a new (go) distribution | ||
|
||
Run: | ||
|
@@ -107,25 +118,27 @@ The optional `sub_package` argument is used to specify a module within a repo. | |
|
||
### Publishing | ||
|
||
In the root of the repository, run: | ||
To produce a CID (`<NEW_HASH>`) that includes binaries for all versions defined in `./dists/`, in the root of the repository, run: | ||
|
||
```sh | ||
> make publish | ||
``` | ||
|
||
This will build any new binaries defined by dist and the website to the `releases` dir, add it to ipfs and patch it into the existing dag for the published dist.ipfs.io. Save the hash it spits out (we'll call it `<NEW_HASH>`), that's the new hash for `dists.ipfs.io`. We also append it to a file called `versions` in the repo root (*not* checked into git). | ||
|
||
Next, you should probably: | ||
- This will build any new binaries defined by dist and the website to the `releases` dir, add it to ipfs and patch it into the existing dag for the published `/ipns/dist.ipfs.io`. | ||
- Versions that are already present on the website will be reused, speeding up the build. | ||
- Updated CID (`<NEW_HASH>`) will be printed at the end. That's the new hash for `dists.ipfs.io`. We also append it to a file called `versions` in the repo root (*not* checked into git). | ||
|
||
1. Load the dists website in your browser to make sure everything looks right: `http://127.0.0.1:8080/ipfs/<NEW_HASH>`. | ||
2. Compare `<NEW_HASH>` with the current `dists.ipfs.io` to make sure nothing is amiss: `ipfs object diff /ipns/dist.ipfs.io /ipfs/<NEW_HASH>` | ||
After the local build is done, make a quick inspection: | ||
|
||
If all looks well, **pin the hash using pinbot** (#ipfs-pinbot on Freenode, ask someone if you don't have permission to do so). | ||
2. Load the dists website in your browser to make sure everything looks right: `http://localhost:8080/ipfs/<NEW_HASH>`. | ||
3. Compare `<NEW_HASH>` with the current `dists.ipfs.io` to make sure nothing is amiss: `ipfs object diff /ipns/dist.ipfs.io /ipfs/<NEW_HASH>` | ||
|
||
Finally, | ||
|
||
1. Commit your changes and make a PR. Specifically, the changes to `dists/<dist>/versions` and `dists/<dist>/current`. | ||
2. Make a PR with an edit on [protocol/infra](https://github.com/protocol/infra/blob/master/dns/config/dist.ipfs.io.yaml) with the hash you got from `make publish` and a link to the PR above. | ||
2. Wait for [Github Action](https://github.com/ipfs/distributions/actions/) on your PR to build **signed** binaries. `<NEW_SIGNED_HASH>` will be different than one from local build. | ||
3. Make a PR with an edit on [protocol/infra](https://github.com/protocol/infra/blob/master/dns/config/dist.ipfs.io.yaml) with `<NEW_SIGNED_HASH>` you got from the Github Action output and a link to the PR above. | ||
- TODO: this step may be automated in the future - see the [discussion](https://github.com/ipfs/distributions/issues/372). | ||
|
||
If you have permission, you can just merge the PR, update the DNS, and then immediately, close the issue on ipfs/infrastructure. Ping someone on IRC. | ||
|
||
|
@@ -194,6 +207,16 @@ So for example, if we had `<dist>` `go-ipfs` and `fs-repo-migrations`, we might | |
|
||
We call this the **distribution index**, the listing of all distributions, their versions, and platform assets. | ||
|
||
### Notes on reproducible builds | ||
|
||
Running `./dockerized make publish` will produce binaries using the same | ||
runtime as CI. The main difference between local build and official CI one is | ||
signing step on platforms such as `darwin` (macOS). | ||
|
||
Signatures are attached at the end of macOS binaries, which means | ||
`*_darwin-*.tar.gz` produced by CI will have additional bytes when compared | ||
with local build. | ||
lidel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Contribute | ||
|
||
Issues and PRs welcome! Please [check out the issues](https://github.com/ipfs/distributions/issues). | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,11 @@ set -euxo pipefail | |
docker pull ubuntu:20.04 | ||
|
||
# CACHEBUST means this will apply the updates once a day | ||
docker build . -t distributions --build-arg CACHEBUST=`date --iso-8601=date` --build-arg USER_UID=$(id -u "$USER") | ||
docker build . -t distributions \ | ||
--build-arg CACHEBUST=`date --iso-8601=date` \ | ||
--build-arg USER_UID=$(id -u "$USER") \ | ||
--build-arg GO_IPFS_VER=${GO_IPFS_VER:-$(curl -s https://dist.ipfs.io/go-ipfs/versions | tail -n 1)} # match http api client version on CI | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ this controls the version of the CLI client inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this comment live in the source file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe the comment on the very right is enough, more context can be found on this PR. |
||
|
||
# We use host networking as the build process assumes a fairly long-lived ipfs | ||
# node has the CIDs (we give them to the collab cluster to pin) | ||
docker run --rm -it --network host -v `pwd`:/build distributions "$@" | ||
docker run --rm -i --network host -e DIST_ROOT -v `pwd`:/build distributions "$@" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#!/usr/bin/env bash | ||
set -e | ||
|
||
PREVIEW_URL="https://dweb.link$CONTENT_PATH" | ||
API_PARAMS=$(jq --monochrome-output --null-input \ | ||
--arg state "success" \ | ||
--arg target_url "$PREVIEW_URL" \ | ||
--arg description "Preview updated website on IPFS" \ | ||
--arg context "Preview is ready" \ | ||
'{ state: $state, target_url: $target_url, description: $description, context: $context }' ) | ||
curl --output /dev/null --silent --show-error \ | ||
-X POST -H "Authorization: Bearer $GITHUB_TOKEN" -H 'Content-Type: application/json' \ | ||
--data "$API_PARAMS" 'https://api.github.com/repos/ipfs/distributions/statuses/${GIT_REVISION}' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ we could replace this script with JS call and |
||
echo "Pinned to IPFS - $PREVIEW_URL" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/usr/bin/env bash | ||
set -e | ||
|
||
echo "::group::pin add" | ||
ipfs-cluster-ctl --enc=json \ | ||
--host "/dnsaddr/ipfs-websites.collab.ipfscluster.io" \ | ||
--basic-auth "${CLUSTER_USER}:${CLUSTER_PASSWORD}" \ | ||
pin add \ | ||
--name "${PIN_NAME}" \ | ||
--no-status $PIN_ADD_EXTRA_ARGS \ | ||
"$PIN_CID" | ||
echo "::endgroup::" | ||
|
||
echo "::group::waiting until pinned" | ||
while true; do | ||
ipfs-cluster-ctl --enc=json \ | ||
--host "/dnsaddr/ipfs-websites.collab.ipfscluster.io" \ | ||
--basic-auth "${CLUSTER_USER}:${CLUSTER_PASSWORD}" \ | ||
status "$PIN_CID" | tee cluster-pin-status | ||
if [[ $(jq '.peer_map[].status' cluster-pin-status | grep '"pinned"' | wc -l) -ge 2 ]]; then | ||
echo "Got 2 pin confirmations, finishing the workflow" | ||
Comment on lines
+20
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ to make CI faster and avoid hanging forever if parts of cluster are out of sync, cluster pinning is considered "done" after we have 2 copies. Here, I do it manually in userland, but filled ipfs-cluster/ipfs-cluster#1427 to add this sort of thing to ipfs-cluster-ctl CLI tool. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to above: when do we decide to put this in the PR vs. the code itself? Do folks tend to do a git blame and look for comments to find more context? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I often use git blame, but in this specific case those comments are provided mostly to make PR review easier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. I'll defer to the team for the standard. I was bringing this up because it was hard for me to imagine a case where a comment is useful during PR where it isn't also useful 6 months in the future when looking at the code with fresh eyes. Anyways, sounds good. |
||
break | ||
else | ||
echo "(sleeping for 15 seconds)" | ||
sleep 15 | ||
fi | ||
done | ||
echo "::endgroup::" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#!/usr/bin/env bash | ||
set -e | ||
|
||
echo "::group::Install go-ipfs and ipfs-cluster-ctl" | ||
curl -s https://dist.ipfs.io/go-ipfs/${GO_IPFS_VER}/go-ipfs_${GO_IPFS_VER}_linux-amd64.tar.gz | sudo tar vzx -C /usr/local/bin/ go-ipfs/ipfs --strip-components=1 | ||
curl -s https://dist.ipfs.io/ipfs-cluster-ctl/${CLUSTER_CTL_VER}/ipfs-cluster-ctl_${CLUSTER_CTL_VER}_linux-amd64.tar.gz | sudo tar vzx -C /usr/local/bin/ ipfs-cluster-ctl/ipfs-cluster-ctl --strip-components=1 | ||
echo "::endgroup::" | ||
|
||
# fix resolv - DNS provided by Github is unreliable for DNSLik/dnsaddr | ||
sudo sed -i -e 's/nameserver 127.0.0.*/nameserver 1.1.1.1/g' /etc/resolv.conf | ||
Comment on lines
+9
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ This was pretty annoying. Entire build failed because Githubs DNS proxying cache at |
||
|
||
# QUIC perf: https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size | ||
sudo sysctl -w net.core.rmem_max=2500000 | ||
|
||
# init ipfs | ||
echo "::group::Set up IPFS daemon" | ||
ipfs init --profile flatfs,server,test,lowpower | ||
# make flatfs async for faster ci | ||
new_config=$( jq '.Datastore.Spec.mounts[0].child.sync = false' ~/.ipfs/config) && echo "${new_config}" > ~/.ipfs/config | ||
# restore deterministic port (changed by test profile) | ||
ipfs config Addresses.API "/ip4/127.0.0.1/tcp/5001" | ||
# wait for ipfs daemon | ||
ipfs daemon --enable-gc=false & while (! ipfs id --api "/ip4/127.0.0.1/tcp/5001"); do sleep 1; done | ||
echo "::endgroup::" | ||
|
||
|
||
echo "::group::Preconnect to cluster peers" | ||
echo '-> preconnect to cluster peers' | ||
ipfs-cluster-ctl --enc=json \ | ||
--host "/dnsaddr/ipfs-websites.collab.ipfscluster.io" \ | ||
--basic-auth "${CLUSTER_USER}:${CLUSTER_PASSWORD}" \ | ||
peers ls > cluster-peers-ls | ||
for maddr in $(jq -r '.[].ipfs.addresses[]?' cluster-peers-ls); do | ||
ipfs swarm connect "$maddr" || continue | ||
done | ||
echo '-> manual connect to cluster.ipfs.io' | ||
ipfs swarm connect /dnsaddr/cluster.ipfs.io | ||
echo '-> list swarm peers' | ||
ipfs swarm peers | ||
echo "::endgroup::" |
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.
What's the process for updating these? Do we rely on someone manually updating it? What's their trigger for doing so?
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 think those are low importance: could be kept as-is until someone cares to update or there is a breaking change that forces version bump.
Having static versions of build tools makes the builds more robust and reproducible, but we could also switch to always run on the latest version for dogfooding – don't feel strongly either way, but leaning towards more reproducibility.