diff --git a/benchmark-bot/controller/install-release b/benchmark-bot/controller/install-release index ef0f69c..a42e887 100755 --- a/benchmark-bot/controller/install-release +++ b/benchmark-bot/controller/install-release @@ -3,6 +3,7 @@ set -euo pipefail archive=${1:?application archive is required} repository_url=${2:?source repository URL is required} +authorized_github_logins=${3:?authorized GitHub logins are required} [[ -f ${archive} ]] || { echo "Application archive does not exist" >&2; exit 2; } unzip -tq "${archive}" @@ -37,6 +38,19 @@ chown --recursive benchmark-bot:benchmark-cache "${source_root}" chmod --recursive g+rX,o-rwx "${source_root}" find "${source_root}" -type d -exec chmod g+s {} + +controller_environment=/var/lib/datafusion-pr-bot/controller.env +if [[ -f ${controller_environment} ]]; then + grep --quiet '^AUTHORIZED_GITHUB_LOGINS=' "${controller_environment}" || { + echo "Controller environment has no GitHub authorization setting" >&2 + exit 2 + } + sed --in-place \ + "s/^AUTHORIZED_GITHUB_LOGINS=.*/AUTHORIZED_GITHUB_LOGINS=${authorized_github_logins}/" \ + "${controller_environment}" + chown benchmark-bot:benchmark-bot "${controller_environment}" + chmod 0600 "${controller_environment}" +fi + if systemctl cat datafusion-pr-bot.service >/dev/null 2>&1; then install --directory --mode 0755 /etc/systemd/system/datafusion-pr-bot.service.d cat > /etc/systemd/system/datafusion-pr-bot.service.d/release.conf <<'SERVICE' diff --git a/benchmark-bot/controller/setup/05-application.sh b/benchmark-bot/controller/setup/05-application.sh index 97bdefd..7680363 100644 --- a/benchmark-bot/controller/setup/05-application.sh +++ b/benchmark-bot/controller/setup/05-application.sh @@ -6,4 +6,5 @@ unzip -p ${application_temporary}/application.zip controller/install-release \ chmod 0755 ${application_temporary}/install-release ${application_temporary}/install-release \ ${application_temporary}/application.zip \ - "{{SOURCE_REPOSITORY_URL}}" + "{{SOURCE_REPOSITORY_URL}}" \ + "{{AUTHORIZED_GITHUB_LOGINS}}" diff --git a/benchmark-bot/infra/controller.ts b/benchmark-bot/infra/controller.ts index a64bc90..af2385c 100644 --- a/benchmark-bot/infra/controller.ts +++ b/benchmark-bot/infra/controller.ts @@ -84,6 +84,7 @@ export function createController(args: ControllerArguments) { }, { dependsOn: [args.application, ...args.identityDependencies], + ignoreChanges: ["ami"], }, ); const publicAddress = new aws.ec2.Eip("bot-controller-address", { diff --git a/benchmark-bot/infra/deployment.ts b/benchmark-bot/infra/deployment.ts index 7f0c348..41093c2 100644 --- a/benchmark-bot/infra/deployment.ts +++ b/benchmark-bot/infra/deployment.ts @@ -10,6 +10,7 @@ export function controllerDeployCommand( key: string, versionId: string, repositoryUrl: string, + authorizedGithubLogins: string[], ): string { return `set -euo pipefail for attempt in $(seq 1 720); do @@ -29,7 +30,8 @@ unzip -p "\${deployment}/application.zip" controller/install-release \ chmod 0755 "\${deployment}/install-release" "\${deployment}/install-release" \ "\${deployment}/application.zip" \ - ${shellQuote(repositoryUrl)} + ${shellQuote(repositoryUrl)} \ + ${shellQuote(authorizedGithubLogins.join(","))} systemctl is-active --quiet datafusion-pr-bot.service`; } @@ -37,6 +39,7 @@ export function deployControllerApplication( controller: aws.ec2.Instance, application: aws.s3.BucketObjectv2, repositoryUrl: string, + authorizedGithubLogins: string[], dependencies: pulumi.Resource[], ): aws.ssm.Association { const commands = pulumi @@ -44,7 +47,13 @@ export function deployControllerApplication( .apply(([bucket, key, versionId]) => { if (!versionId) throw new Error("Controller application has no S3 version"); - return controllerDeployCommand(bucket, key, versionId, repositoryUrl); + return controllerDeployCommand( + bucket, + key, + versionId, + repositoryUrl, + authorizedGithubLogins, + ); }); return new aws.ssm.Association( diff --git a/benchmark-bot/infra/foundation.ts b/benchmark-bot/infra/foundation.ts index 3735e18..3c6ab78 100644 --- a/benchmark-bot/infra/foundation.ts +++ b/benchmark-bot/infra/foundation.ts @@ -72,6 +72,7 @@ export function createControllerInfrastructure(config: ControllerConfig) { controller, application, config.sourceRepositoryUrl, + config.authorizedGithubLogins, [identity.policy, identity.ssmAttachment], ); return { diff --git a/benchmark-bot/test/infrastructure.test.ts b/benchmark-bot/test/infrastructure.test.ts index d394d5f..3cf9a92 100644 --- a/benchmark-bot/test/infrastructure.test.ts +++ b/benchmark-bot/test/infrastructure.test.ts @@ -153,6 +153,7 @@ test("deploys every controller archive through Systems Manager", () => { assert.match(commands, /--version-id 'version-123'/); assert.match(commands, /controller\/install-release/); assert.match(commands, /https:\/\/example\.invalid\/repository\.git/); + assert.match(commands, /'maintainer'/); assert.match(commands, /systemctl is-active --quiet datafusion-pr-bot/); }); @@ -240,6 +241,10 @@ test("installs protected controller state and verified native toolchains", () => assert.match(userData, /install .*\/usr\/local\/bin\/kubectl/); assert.match(userData, /install .*\/usr\/local\/bin\/helm/); assert.match(userData, /controller\/install-release/); + assert.match( + userData, + /application\.zip \\\n+ "https:\/\/example\.invalid\/repository\.git" \\\n+ "maintainer"/, + ); assert.match( userData, /DATAFUSION_SOURCE_ROOT=\/opt\/datafusion-pr-bot\/datafusion-distributed/, diff --git a/benchmark-bot/test/security.test.ts b/benchmark-bot/test/security.test.ts index c992fcb..b8996d1 100644 --- a/benchmark-bot/test/security.test.ts +++ b/benchmark-bot/test/security.test.ts @@ -53,6 +53,9 @@ test("keeps the shared release installer valid", () => { assert.match(script, /UMask=0027/); assert.match(script, /systemctl daemon-reload/); assert.match(script, /systemctl restart datafusion-pr-bot/); + assert.match(script, /\^AUTHORIZED_GITHUB_LOGINS=/); + assert.match(script, /sed --in-place/); + assert.match(script, /chmod 0600 "\$\{controller_environment\}"/); }); test("isolates the shared harness build from controller credentials", () => {