Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-gitlab-credentials.md
Original file line number Diff line number Diff line change
@@ -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.
21 changes: 20 additions & 1 deletion examples/openwiki-update.gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}" \
Expand Down
27 changes: 27 additions & 0 deletions test/gitlab-example-security.test.ts
Original file line number Diff line number Diff line change
@@ -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"',
);
});
});