gpg sign bottles

This commit is contained in:
Jacob Heider 2022-11-24 22:32:26 -05:00 committed by Jacob Heider
parent ea20c7a621
commit e582b03fe6
3 changed files with 48 additions and 1 deletions

View file

@ -197,15 +197,25 @@ jobs:
- run: tar xzf artifacts.tgz
working-directory: ${{ steps.tea.outputs.prefix }}
- run: |
tea +gnupg.org gpg-agent --daemon || true
echo $GPG_PRIVATE_KEY | \
base64 -d | \
tea +gnupg.org gpg --import --batch --yes
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
- run: scripts/bottle.ts ${{ needs.build.outputs.built }}
id: bottle-xz
env:
COMPRESSION: xz
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
- run: scripts/bottle.ts ${{ needs.build.outputs.built }}
id: bottle-gz
env:
COMPRESSION: gz
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
- name: upload bottles
id: upload
@ -214,6 +224,7 @@ jobs:
--srcs ${{ needs.build.outputs.srcs }} ${{ needs.build.outputs.srcs }}
--bottles ${{ steps.bottle-gz.outputs.bottles }} ${{ steps.bottle-xz.outputs.bottles }}
--checksums ${{ steps.bottle-gz.outputs.checksums }} ${{ steps.bottle-xz.outputs.checksums }}
--signatures ${{ steps.bottle-gz.outputs.signatures }} ${{ steps.bottle-xz.outputs.signatures }}
env:
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}

View file

@ -5,6 +5,7 @@ dependencies:
gnu.org/tar: ^1.34
tukaani.org/xz: ^5
zlib.net: 1
gnupg.org: ^2
args:
- deno
- run
@ -18,9 +19,10 @@ args:
import { Installation } from "types"
import { useCellar, usePrefix, useFlags, useCache } from "hooks"
import { run } from "utils"
import { backticks, run } from "utils"
import { crypto } from "deno/crypto/mod.ts"
import { encode } from "deno/encoding/hex.ts"
import { encode as base64Encode } from "deno/encoding/base64.ts"
import { set_output } from "./utils/gha.ts"
import * as ARGV from "./utils/args.ts"
import Path from "path"
@ -34,7 +36,11 @@ if (import.meta.main) {
useFlags()
const compression = Deno.env.get("COMPRESSION") == 'xz' ? 'xz' : 'gz'
const gpgKey = Deno.env.get("GPG_KEY_ID")
const gpgPassphrase = Deno.env.get("GPG_PASSPHRASE")
if (!gpgKey || !gpgPassphrase) throw new Error("missing GPG_KEY_ID")
const checksums: string[] = []
const signatures: string[] = []
const bottles: Path[] = []
for await (const pkg of ARGV.pkgs()) {
@ -43,15 +49,18 @@ if (import.meta.main) {
const installation = await cellar.resolve(pkg)
const path = await bottle(installation, compression)
const checksum = await sha256(path)
const signature = await gpg(path, { gpgKey, gpgPassphrase })
console.log({ bottled: path })
bottles.push(path)
checksums.push(checksum)
signatures.push(signature)
}
await set_output("bottles", bottles)
await set_output("checksums", checksums)
await set_output("signatures", signatures)
}
@ -70,3 +79,26 @@ export async function sha256(file: Path): Promise<string> {
.then(file => crypto.subtle.digest("SHA-256", file.readable))
.then(buf => new TextDecoder().decode(encode(new Uint8Array(buf))))
}
interface GPGCredentials {
gpgKey: string
gpgPassphrase: string
}
async function gpg(file: Path, { gpgKey, gpgPassphrase }: GPGCredentials): Promise<string> {
const rv = await backticks({
cmd: [
"gpg",
"--detach-sign",
"--armor",
"--output",
"-",
"--local-user",
gpgKey,
"--passphrase",
gpgPassphrase,
file.string
]
})
return base64Encode(rv)
}

View file

@ -16,6 +16,7 @@ import { useCache, useFlags, useOffLicense, usePrefix } from "hooks"
import { Package, PackageRequirement } from "types"
import SemVer, * as semver from "semver"
import { basename, dirname } from "deno/path/mod.ts"
import { decode as base64Decode } from "deno/encoding/base64.ts"
import Path from "path"
import { set_output } from "./utils/gha.ts"
import { sha256 } from "./bottle.ts"
@ -101,12 +102,14 @@ const pkgs = args_get("pkgs").map(pkgutils.parse).map(assert_pkg)
const srcs = args_get("srcs")
const bottles = args_get("bottles")
const checksums = args_get("checksums")
const signatures = args_get("signatures")
const rv: string[] = []
for (const [index, pkg] of pkgs.entries()) {
const bottle = new Path(bottles[index])
const checksum = checksums[index]
const signature = base64Decode(signatures[index])
const stowed = cache.decode(bottle)!
const key = useOffLicense("s3").key(stowed)
const versions = await get_versions(key, pkg, bucket)
@ -114,6 +117,7 @@ for (const [index, pkg] of pkgs.entries()) {
//FIXME stream the bottle (at least) to S3
await put(key, bottle, bucket)
await put(`${key}.sha256sum`, `${checksum} ${basename(key)}`, bucket)
await put(`${key}.asc`, signature, bucket)
await put(`${dirname(key)}/versions.txt`, versions.join("\n"), bucket)
// mirror the sources