Skip to content

Commit bb24e07

Browse files
CopilotBarkinKctp
andauthored
fix: bypass determine_name/email GET /user calls with bind-mounted override scripts
GitHub App installation tokens cannot call GET /user or GET /user/emails (those endpoints require a user-scoped PAT). The packaging containers call those endpoints via determine_name and determine_email. Instead of requiring a PAT, write tiny override scripts on the host and bind-mount them over /scripts/determine_name and /scripts/determine_email inside the container. The overrides just echo the supplied actor identity without any API call. - Add --actor_name / --actor_email params to citus_package.py - In build_package(): when both params are set, write override scripts to a temp dir and add -v mounts to the docker command; clean up in finally block - Update workflow to use App token for all git ops and pass --actor_name 'github-actions[bot]' / --actor_email for the containers Agent-Logs-Url: https://github.com/citusdata/tools/sessions/fdb492ee-94bb-42dc-a5d3-56e2d4b2f40b Co-authored-by: BarkinKctp <181959180+BarkinKctp@users.noreply.github.com>
1 parent ec214f0 commit bb24e07

2 files changed

Lines changed: 78 additions & 22 deletions

File tree

.github/workflows/build-citus-community-nightlies.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ env:
44
MAIN_BRANCH: "all-citus"
55
PACKAGING_PASSPHRASE: ${{ secrets.PACKAGING_PASSPHRASE }}
66
PACKAGING_SECRET_KEY: ${{ secrets.PACKAGING_SECRET_KEY }}
7-
GH_TOKEN: ${{ secrets.GH_TOKEN }}
87
DOCKERHUB_USER_NAME: ${{ secrets.DOCKERHUB_USER_NAME }}
98
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
109
on:
@@ -32,9 +31,25 @@ jobs:
3231
- ubuntu/jammy
3332

3433
steps:
34+
35+
- name: Create GitHub App token
36+
id: app
37+
uses: actions/create-github-app-token@v1
38+
with:
39+
app-id: ${{ vars.GH_APP_ID }}
40+
private-key: ${{ secrets.GH_APP_KEY }}
41+
owner: ${{ github.repository_owner }}
42+
43+
- name: Set GH_TOKEN for all steps
44+
run: echo "GH_TOKEN=${{ steps.app.outputs.token }}" >> $GITHUB_ENV
45+
46+
- name: Configure git with x-access-token
47+
run: git config --global url."https://x-access-token:${{ steps.app.outputs.token }}@github.com/".insteadOf "https://github.com/"
48+
3549
- name: Checkout repository
3650
uses: actions/checkout@v3
3751
with:
52+
token: ${{ steps.app.outputs.token }}
3853
fetch-depth: 1
3954
path: tools
4055

@@ -46,7 +61,7 @@ jobs:
4661
password: ${{ secrets.DOCKERHUB_PASSWORD }}
4762

4863
- name: Clone build branch
49-
run: git clone -b "${MAIN_BRANCH}" --depth=1 https://github.com/citusdata/packaging.git packaging
64+
run: git clone -b "${MAIN_BRANCH}" --depth=1 https://github.com/citusdata/packaging.git packaging
5065

5166
- name: Install package dependencies
5267
run: sudo apt-get update && sudo apt-get install libcurl4-openssl-dev libssl-dev python3-testresources
@@ -58,7 +73,8 @@ jobs:
5873
run: |
5974
python -m tools.packaging_automation.citus_package \
6075
--gh_token "${GH_TOKEN}" \
61-
--container_gh_token "${GH_TOKEN}" \
76+
--actor_name "github-actions[bot]" \
77+
--actor_email "41898282+github-actions[bot]@users.noreply.github.com" \
6278
--platform "${{ matrix.platform }}" \
6379
--build_type "nightly" \
6480
--secret_key "${PACKAGING_SECRET_KEY}" \

packaging_automation/citus_package.py

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import argparse
22
import glob
33
import os
4+
import shlex
5+
import shutil
46
import subprocess
7+
import tempfile
58
from enum import Enum
69
from typing import Dict
710
from typing import List
@@ -338,34 +341,62 @@ def build_package(
338341
postgres_version: str,
339342
input_output_parameters: InputOutputParameters,
340343
is_test: bool = False,
341-
container_gh_token: str = "",
344+
actor_name: str = "",
345+
actor_email: str = "",
342346
):
343347
docker_image_name = "packaging" if not is_test else "packaging-test"
344348
postgres_extension = "all" if postgres_version == "all" else f"pg{postgres_version}"
345-
# Packaging containers call GET /user and GET /user/emails via determine_name/determine_email.
346-
# Those endpoints require a user-scoped token (PAT). GitHub App installation tokens are
347-
# repository-scoped and will receive a 403 for user endpoints, so a separate PAT token is
348-
# used for the container when provided.
349-
os.environ["GITHUB_TOKEN"] = container_gh_token if container_gh_token else github_token
349+
os.environ["GITHUB_TOKEN"] = github_token
350350
os.environ["CONTAINER_BUILD_RUN_ENABLED"] = "true"
351351
if not os.path.exists(input_output_parameters.output_dir):
352352
os.makedirs(input_output_parameters.output_dir)
353353

354+
# When an actor name and email are provided (e.g. when running under a GitHub App
355+
# installation token), we shadow the /scripts/determine_name and
356+
# /scripts/determine_email scripts inside the container with tiny override scripts
357+
# that just echo the supplied values. This avoids the GET /user and GET /user/emails
358+
# API calls that those scripts make, which fail with 403 when the token is a GitHub
359+
# App installation token (not a user-scoped PAT).
360+
actor_tmpdir = None
361+
actor_mounts = ""
362+
if actor_name and actor_email:
363+
actor_tmpdir = tempfile.mkdtemp(prefix="citus_pkg_actor_")
364+
for script_name, value in [
365+
("determine_name", actor_name),
366+
("determine_email", actor_email),
367+
]:
368+
script_path = os.path.join(actor_tmpdir, script_name)
369+
with open(script_path, "w", encoding="utf-8") as f:
370+
f.write(f"#!/bin/bash\nprintf '%s\\n' {shlex.quote(value)}\n")
371+
os.chmod(script_path, 0o755)
372+
actor_mounts = (
373+
f"-v {actor_tmpdir}/determine_name:/scripts/determine_name:ro "
374+
f"-v {actor_tmpdir}/determine_email:/scripts/determine_email:ro "
375+
)
376+
354377
docker_command = (
355-
f"docker run --rm -v {input_output_parameters.output_dir}:/packages -v "
378+
f"docker run --rm {actor_mounts}"
379+
f"-v {input_output_parameters.output_dir}:/packages -v "
356380
f"{input_output_parameters.input_files_dir}:/buildfiles:ro "
357381
f"-e GITHUB_TOKEN -e PACKAGE_ENCRYPTION_KEY -e UNENCRYPTED_PACKAGE -e CONTAINER_BUILD_RUN_ENABLED "
358382
f"-e MSRUSTUP_PAT -e CRATES_IO_MIRROR_FEED_TOKEN -e INSTALL_RUST -e CI "
359383
f"citus/{docker_image_name}:{docker_platform}-{postgres_extension} {build_type.name}"
360384
)
361385

362386
print(f"Executing docker command: {docker_command}")
363-
output = run_with_output(docker_command, text=True)
387+
try:
388+
output = run_with_output(docker_command, text=True)
389+
finally:
390+
if actor_tmpdir:
391+
shutil.rmtree(actor_tmpdir, ignore_errors=True)
364392

365-
if output.stdout:
366-
print("Output:" + output.stdout)
367393
if output.returncode != 0:
368-
raise ValueError(output.stderr)
394+
raise ValueError(
395+
"Docker command failed.\n"
396+
f"Command: {docker_command}\n"
397+
f"Exit code: {output.returncode}\n"
398+
f"--- combined output (stdout+stderr) ---\n{output.stdout}\n"
399+
)
369400

370401
if input_output_parameters.output_validation:
371402
validate_output(
@@ -405,7 +436,8 @@ def build_packages(
405436
signing_credentials: SigningCredentials,
406437
input_output_parameters: InputOutputParameters,
407438
is_test: bool = False,
408-
container_gh_token: str = "",
439+
actor_name: str = "",
440+
actor_email: str = "",
409441
) -> None:
410442
os_name, os_version = decode_os_and_release(platform)
411443
release_versions, nightly_versions = get_postgres_versions(
@@ -454,7 +486,8 @@ def build_packages(
454486
postgres_docker_extension,
455487
input_output_parameters,
456488
is_test,
457-
container_gh_token,
489+
actor_name,
490+
actor_email,
458491
)
459492
print(
460493
f"Package build for {os_name}-{os_version} for postgres {postgres_docker_extension} finished "
@@ -528,13 +561,19 @@ def tear_release_stage_from_package_version(package_version: str) -> str:
528561
parser = argparse.ArgumentParser()
529562
parser.add_argument("--gh_token", required=True)
530563
parser.add_argument(
531-
"--container_gh_token",
564+
"--actor_name",
565+
required=False,
566+
default="",
567+
help="Committer name written into package changelogs. When set together with "
568+
"--actor_email, the packaging container's determine_name and determine_email "
569+
"scripts are overridden so that GET /user is never called. This allows "
570+
"GitHub App installation tokens to be used without a PAT.",
571+
)
572+
parser.add_argument(
573+
"--actor_email",
532574
required=False,
533575
default="",
534-
help="Token used as GITHUB_TOKEN inside packaging containers. "
535-
"Defaults to --gh_token when not set. Must be a user-scoped token "
536-
"(PAT) because the packaging scripts call GET /user and GET /user/emails, "
537-
"which are not accessible with GitHub App installation tokens.",
576+
help="Committer email written into package changelogs. See --actor_name.",
538577
)
539578
parser.add_argument("--platform", required=False, choices=platform_names())
540579
parser.add_argument(
@@ -567,5 +606,6 @@ def tear_release_stage_from_package_version(package_version: str) -> str:
567606
sign_credentials,
568607
io_parameters,
569608
args.is_test,
570-
args.container_gh_token,
609+
args.actor_name,
610+
args.actor_email,
571611
)

0 commit comments

Comments
 (0)