mirror of
https://github.com/ivabus/pantry
synced 2024-11-26 18:25:08 +03:00
gpg sign bottles
This commit is contained in:
parent
ea20c7a621
commit
e582b03fe6
3 changed files with 48 additions and 1 deletions
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
|
@ -197,15 +197,25 @@ jobs:
|
||||||
- run: tar xzf artifacts.tgz
|
- run: tar xzf artifacts.tgz
|
||||||
working-directory: ${{ steps.tea.outputs.prefix }}
|
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 }}
|
- run: scripts/bottle.ts ${{ needs.build.outputs.built }}
|
||||||
id: bottle-xz
|
id: bottle-xz
|
||||||
env:
|
env:
|
||||||
COMPRESSION: xz
|
COMPRESSION: xz
|
||||||
|
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
|
||||||
|
|
||||||
- run: scripts/bottle.ts ${{ needs.build.outputs.built }}
|
- run: scripts/bottle.ts ${{ needs.build.outputs.built }}
|
||||||
id: bottle-gz
|
id: bottle-gz
|
||||||
env:
|
env:
|
||||||
COMPRESSION: gz
|
COMPRESSION: gz
|
||||||
|
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
|
||||||
|
|
||||||
- name: upload bottles
|
- name: upload bottles
|
||||||
id: upload
|
id: upload
|
||||||
|
@ -214,6 +224,7 @@ jobs:
|
||||||
--srcs ${{ needs.build.outputs.srcs }} ${{ needs.build.outputs.srcs }}
|
--srcs ${{ needs.build.outputs.srcs }} ${{ needs.build.outputs.srcs }}
|
||||||
--bottles ${{ steps.bottle-gz.outputs.bottles }} ${{ steps.bottle-xz.outputs.bottles }}
|
--bottles ${{ steps.bottle-gz.outputs.bottles }} ${{ steps.bottle-xz.outputs.bottles }}
|
||||||
--checksums ${{ steps.bottle-gz.outputs.checksums }} ${{ steps.bottle-xz.outputs.checksums }}
|
--checksums ${{ steps.bottle-gz.outputs.checksums }} ${{ steps.bottle-xz.outputs.checksums }}
|
||||||
|
--signatures ${{ steps.bottle-gz.outputs.signatures }} ${{ steps.bottle-xz.outputs.signatures }}
|
||||||
env:
|
env:
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
||||||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
|
|
|
@ -5,6 +5,7 @@ dependencies:
|
||||||
gnu.org/tar: ^1.34
|
gnu.org/tar: ^1.34
|
||||||
tukaani.org/xz: ^5
|
tukaani.org/xz: ^5
|
||||||
zlib.net: 1
|
zlib.net: 1
|
||||||
|
gnupg.org: ^2
|
||||||
args:
|
args:
|
||||||
- deno
|
- deno
|
||||||
- run
|
- run
|
||||||
|
@ -18,9 +19,10 @@ args:
|
||||||
|
|
||||||
import { Installation } from "types"
|
import { Installation } from "types"
|
||||||
import { useCellar, usePrefix, useFlags, useCache } from "hooks"
|
import { useCellar, usePrefix, useFlags, useCache } from "hooks"
|
||||||
import { run } from "utils"
|
import { backticks, run } from "utils"
|
||||||
import { crypto } from "deno/crypto/mod.ts"
|
import { crypto } from "deno/crypto/mod.ts"
|
||||||
import { encode } from "deno/encoding/hex.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 { set_output } from "./utils/gha.ts"
|
||||||
import * as ARGV from "./utils/args.ts"
|
import * as ARGV from "./utils/args.ts"
|
||||||
import Path from "path"
|
import Path from "path"
|
||||||
|
@ -34,7 +36,11 @@ if (import.meta.main) {
|
||||||
useFlags()
|
useFlags()
|
||||||
|
|
||||||
const compression = Deno.env.get("COMPRESSION") == 'xz' ? 'xz' : 'gz'
|
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 checksums: string[] = []
|
||||||
|
const signatures: string[] = []
|
||||||
const bottles: Path[] = []
|
const bottles: Path[] = []
|
||||||
|
|
||||||
for await (const pkg of ARGV.pkgs()) {
|
for await (const pkg of ARGV.pkgs()) {
|
||||||
|
@ -43,15 +49,18 @@ if (import.meta.main) {
|
||||||
const installation = await cellar.resolve(pkg)
|
const installation = await cellar.resolve(pkg)
|
||||||
const path = await bottle(installation, compression)
|
const path = await bottle(installation, compression)
|
||||||
const checksum = await sha256(path)
|
const checksum = await sha256(path)
|
||||||
|
const signature = await gpg(path, { gpgKey, gpgPassphrase })
|
||||||
|
|
||||||
console.log({ bottled: path })
|
console.log({ bottled: path })
|
||||||
|
|
||||||
bottles.push(path)
|
bottles.push(path)
|
||||||
checksums.push(checksum)
|
checksums.push(checksum)
|
||||||
|
signatures.push(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
await set_output("bottles", bottles)
|
await set_output("bottles", bottles)
|
||||||
await set_output("checksums", checksums)
|
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(file => crypto.subtle.digest("SHA-256", file.readable))
|
||||||
.then(buf => new TextDecoder().decode(encode(new Uint8Array(buf))))
|
.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)
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import { useCache, useFlags, useOffLicense, usePrefix } from "hooks"
|
||||||
import { Package, PackageRequirement } from "types"
|
import { Package, PackageRequirement } from "types"
|
||||||
import SemVer, * as semver from "semver"
|
import SemVer, * as semver from "semver"
|
||||||
import { basename, dirname } from "deno/path/mod.ts"
|
import { basename, dirname } from "deno/path/mod.ts"
|
||||||
|
import { decode as base64Decode } from "deno/encoding/base64.ts"
|
||||||
import Path from "path"
|
import Path from "path"
|
||||||
import { set_output } from "./utils/gha.ts"
|
import { set_output } from "./utils/gha.ts"
|
||||||
import { sha256 } from "./bottle.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 srcs = args_get("srcs")
|
||||||
const bottles = args_get("bottles")
|
const bottles = args_get("bottles")
|
||||||
const checksums = args_get("checksums")
|
const checksums = args_get("checksums")
|
||||||
|
const signatures = args_get("signatures")
|
||||||
|
|
||||||
const rv: string[] = []
|
const rv: string[] = []
|
||||||
|
|
||||||
for (const [index, pkg] of pkgs.entries()) {
|
for (const [index, pkg] of pkgs.entries()) {
|
||||||
const bottle = new Path(bottles[index])
|
const bottle = new Path(bottles[index])
|
||||||
const checksum = checksums[index]
|
const checksum = checksums[index]
|
||||||
|
const signature = base64Decode(signatures[index])
|
||||||
const stowed = cache.decode(bottle)!
|
const stowed = cache.decode(bottle)!
|
||||||
const key = useOffLicense("s3").key(stowed)
|
const key = useOffLicense("s3").key(stowed)
|
||||||
const versions = await get_versions(key, pkg, bucket)
|
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
|
//FIXME stream the bottle (at least) to S3
|
||||||
await put(key, bottle, bucket)
|
await put(key, bottle, bucket)
|
||||||
await put(`${key}.sha256sum`, `${checksum} ${basename(key)}`, 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)
|
await put(`${dirname(key)}/versions.txt`, versions.join("\n"), bucket)
|
||||||
|
|
||||||
// mirror the sources
|
// mirror the sources
|
||||||
|
|
Loading…
Reference in a new issue