From 9e4da3f04a9ddea9a72f961392479277a9ea2892 Mon Sep 17 00:00:00 2001 From: John Kennedy <65985482+jkennedyvz@users.noreply.github.com> Date: Wed, 5 Aug 2026 22:15:35 +0000 Subject: [PATCH] fix: secure GitLab example Git authentication Co-authored-by: open-swe[bot] --- .changeset/quiet-gitlab-credentials.md | 5 +++++ examples/openwiki-update.gitlab-ci.yml | 21 +++++++++++++++++++- test/gitlab-example-security.test.ts | 27 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .changeset/quiet-gitlab-credentials.md create mode 100644 test/gitlab-example-security.test.ts diff --git a/.changeset/quiet-gitlab-credentials.md b/.changeset/quiet-gitlab-credentials.md new file mode 100644 index 00000000..ccad3782 --- /dev/null +++ b/.changeset/quiet-gitlab-credentials.md @@ -0,0 +1,5 @@ +--- +"openwiki": patch +--- + +Use an ephemeral credential helper in the GitLab CI example so push credentials cannot persist in remote URLs or appear under shell tracing. diff --git a/examples/openwiki-update.gitlab-ci.yml b/examples/openwiki-update.gitlab-ci.yml index d971dcaa..a4b7ebe5 100644 --- a/examples/openwiki-update.gitlab-ci.yml +++ b/examples/openwiki-update.gitlab-ci.yml @@ -21,7 +21,26 @@ openwiki_update: - git checkout -b "$OPENWIKI_BRANCH" - git add openwiki AGENTS.md CLAUDE.md .github/workflows/openwiki-update.yml - git commit -m "docs: update OpenWiki" - - git push "https://oauth2:${OPENWIKI_GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "$OPENWIKI_BRANCH" + - | + # Configure OPENWIKI_GITLAB_TOKEN as a protected, masked CI/CD variable. + # Keep tracing disabled while the temporary helper can read the token. + set +x + credential_helper="$(mktemp)" + trap 'rm -f "$credential_helper"' EXIT + chmod 700 "$credential_helper" + cat > "$credential_helper" <<'EOF' + #!/bin/sh + case "$1" in + get) + printf 'username=%s\n' oauth2 + printf 'password=%s\n' "$OPENWIKI_GITLAB_TOKEN" + ;; + esac + EOF + git -c credential.helper= -c credential.helper="$credential_helper" \ + push "https://${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "$OPENWIKI_BRANCH" + rm -f "$credential_helper" + trap - EXIT - | curl --fail --request POST \ --header "PRIVATE-TOKEN: ${OPENWIKI_GITLAB_TOKEN}" \ diff --git a/test/gitlab-example-security.test.ts b/test/gitlab-example-security.test.ts new file mode 100644 index 00000000..afffdfcf --- /dev/null +++ b/test/gitlab-example-security.test.ts @@ -0,0 +1,27 @@ +import { readFile } from "node:fs/promises"; +import { describe, expect, test } from "vitest"; +import { parse } from "yaml"; + +const examplePath = new URL( + "../examples/openwiki-update.gitlab-ci.yml", + import.meta.url, +); + +describe("GitLab CI example", () => { + test("keeps Git credentials out of remote URLs and traced commands", async () => { + const example = await readFile(examplePath, "utf8"); + const config = parse(example) as { + openwiki_update?: { script?: unknown[] }; + }; + + expect(config.openwiki_update?.script).toBeInstanceOf(Array); + expect(example).not.toMatch(/https?:\/\/[^/\s]+@/u); + expect(example).toContain("set +x"); + expect(example).toContain('credential.helper="$credential_helper"'); + expect(example).toContain("<<'EOF'"); + expect(example).toContain('"$OPENWIKI_GITLAB_TOKEN"'); + expect(example).toContain( + 'push "https://${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"', + ); + }); +});