feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
145
scripts/ci/create-mobile-release-evidence.mjs
Normal file
145
scripts/ci/create-mobile-release-evidence.mjs
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
import { spawnSync } from 'node:child_process'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import {
|
||||
buildReleasePayload,
|
||||
createImmutableVerificationSnapshot,
|
||||
hashRegularFileStable,
|
||||
readSmallFileStable,
|
||||
releaseBoundaryFail,
|
||||
signReleaseEvidence,
|
||||
writeJsonCreateOnly,
|
||||
} from './mobile-release-evidence-lib.mjs'
|
||||
|
||||
function parseArguments(argv) {
|
||||
const allowed = new Set([
|
||||
'aab',
|
||||
'apk',
|
||||
'bundletool',
|
||||
'commit-sha',
|
||||
'expected-admob-app-id',
|
||||
'expected-upload-cert-sha256',
|
||||
'expected-version-code',
|
||||
'expected-version-name',
|
||||
'git-ref',
|
||||
'private-key',
|
||||
'repository',
|
||||
'run-attempt',
|
||||
'run-id',
|
||||
'runner-identity',
|
||||
'snapshot-dir',
|
||||
'tree-sha',
|
||||
'workflow-identity',
|
||||
])
|
||||
const result = {}
|
||||
for (let index = 0; index < argv.length; index += 2) {
|
||||
const flag = argv[index]
|
||||
const value = argv[index + 1]
|
||||
if (!flag?.startsWith('--') || !value || value.startsWith('--')) {
|
||||
releaseBoundaryFail('create_evidence_arguments_invalid')
|
||||
}
|
||||
const name = flag.slice(2)
|
||||
if (!allowed.has(name) || Object.hasOwn(result, name)) {
|
||||
releaseBoundaryFail(`create_evidence_argument_rejected_${name}`)
|
||||
}
|
||||
result[name] = value
|
||||
}
|
||||
for (const name of allowed) {
|
||||
if (!result[name]) releaseBoundaryFail(`create_evidence_argument_missing_${name}`)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const options = parseArguments(process.argv.slice(2))
|
||||
const scriptDirectory = dirname(fileURLToPath(import.meta.url))
|
||||
const verifier = resolve(scriptDirectory, 'verify-android-artifact.mjs')
|
||||
const bundletool = resolve(options.bundletool)
|
||||
const snapshot = createImmutableVerificationSnapshot({
|
||||
apkPath: resolve(options.apk),
|
||||
aabPath: resolve(options.aab),
|
||||
destinationDirectory: resolve(options['snapshot-dir']),
|
||||
verifierPath: verifier,
|
||||
bundletoolPath: bundletool,
|
||||
})
|
||||
const verifierBefore = hashRegularFileStable(snapshot.verifierPath)
|
||||
const bundletoolBefore = hashRegularFileStable(snapshot.bundletoolPath)
|
||||
const verifierArguments = [
|
||||
snapshot.verifierPath,
|
||||
'--mode', 'release',
|
||||
'--apk', snapshot.apkPath,
|
||||
'--aab', snapshot.aabPath,
|
||||
'--bundletool', snapshot.bundletoolPath,
|
||||
'--expected-admob-app-id', options['expected-admob-app-id'],
|
||||
'--expected-upload-cert-sha256', options['expected-upload-cert-sha256'],
|
||||
'--expected-version-name', options['expected-version-name'],
|
||||
'--expected-version-code', options['expected-version-code'],
|
||||
]
|
||||
const verificationRun = spawnSync(process.execPath, verifierArguments, {
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 32 * 1024 * 1024,
|
||||
windowsHide: true,
|
||||
})
|
||||
if (verificationRun.status !== 0) {
|
||||
const detail = String(verificationRun.stderr || verificationRun.stdout)
|
||||
.trim()
|
||||
.replace(/\s+/g, '_')
|
||||
.slice(0, 500)
|
||||
releaseBoundaryFail(`release_artifact_verifier_failed_${detail}`)
|
||||
}
|
||||
const verifierAfter = hashRegularFileStable(snapshot.verifierPath)
|
||||
const bundletoolAfter = hashRegularFileStable(snapshot.bundletoolPath)
|
||||
if (verifierBefore.sha256 !== verifierAfter.sha256 || verifierBefore.bytes !== verifierAfter.bytes) {
|
||||
releaseBoundaryFail('verifier_changed_during_verification')
|
||||
}
|
||||
if (bundletoolBefore.sha256 !== bundletoolAfter.sha256 || bundletoolBefore.bytes !== bundletoolAfter.bytes) {
|
||||
releaseBoundaryFail('bundletool_changed_during_verification')
|
||||
}
|
||||
let verification
|
||||
try {
|
||||
verification = JSON.parse(verificationRun.stdout)
|
||||
} catch {
|
||||
releaseBoundaryFail('release_artifact_verifier_json_invalid')
|
||||
}
|
||||
const expected = {
|
||||
versionName: options['expected-version-name'],
|
||||
versionCode: options['expected-version-code'],
|
||||
adMobAppId: options['expected-admob-app-id'],
|
||||
signerSha256: options['expected-upload-cert-sha256'],
|
||||
}
|
||||
const provenance = {
|
||||
repository: options.repository,
|
||||
commitSha: options['commit-sha'],
|
||||
treeSha: options['tree-sha'],
|
||||
gitRef: options['git-ref'],
|
||||
workflowIdentity: options['workflow-identity'],
|
||||
runId: options['run-id'],
|
||||
runAttempt: options['run-attempt'],
|
||||
runnerIdentity: options['runner-identity'],
|
||||
verifierSha256: verifierBefore.sha256,
|
||||
bundletoolSha256: bundletoolBefore.sha256,
|
||||
}
|
||||
const payload = buildReleasePayload({
|
||||
verification,
|
||||
apkPath: snapshot.apkPath,
|
||||
aabPath: snapshot.aabPath,
|
||||
expected,
|
||||
provenance,
|
||||
})
|
||||
const privateKeyPem = readSmallFileStable(options['private-key'], 64 * 1024)
|
||||
const evidence = signReleaseEvidence(payload, privateKeyPem)
|
||||
|
||||
// Both files are create-only. A rerun must start from a clean build output,
|
||||
// never overwrite evidence that may already have been consumed downstream.
|
||||
writeJsonCreateOnly(join(snapshot.destination, 'release-artifact-verification.json'), verification)
|
||||
writeJsonCreateOnly(join(snapshot.destination, 'release-artifact-evidence.json'), evidence)
|
||||
process.stdout.write(`${JSON.stringify({
|
||||
ok: true,
|
||||
mode: payload.mode,
|
||||
packageName: payload.packageName,
|
||||
versionName: payload.versionName,
|
||||
versionCode: payload.versionCode,
|
||||
apkSha256: payload.apk.sha256,
|
||||
aabSha256: payload.aab.sha256,
|
||||
evidenceKeyId: evidence.signature.keyId,
|
||||
provenance: payload.provenance,
|
||||
})}\n`)
|
||||
Loading…
Add table
Add a link
Reference in a new issue