Skip to content

governance: consolidate perfops-consulting-site into the monorepo (site/)#31

Merged
muntianus merged 5 commits into
mainfrom
governance/consolidate-consulting-site
May 30, 2026
Merged

governance: consolidate perfops-consulting-site into the monorepo (site/)#31
muntianus merged 5 commits into
mainfrom
governance/consolidate-consulting-site

Conversation

@muntianus
Copy link
Copy Markdown
Owner

Clean replacement for #30 (that branch was the stale post-squash consolidation
branch and conflicted with main by re-adding 20 already-merged files). This
branch is cut fresh from main, so the only diff is the new script + two review
fixes — no conflict.

New: governance/operations/collapse-consulting-site.sh

Full consolidation of the public Next.js site into the monorepo (run it in your
shell — MCP cannot git subtree):

  1. git subtree add --prefix=site — merges perfops-consulting-site into
    site/, full history preserved.
  2. Relocates the manual prod-deploy to the monorepo root as
    .github/workflows/deploy-site.yml, path-adjusted for site/
    (working-directory: site, cache-dependency-path: site/package-lock.json,
    scp source: prefixed with site/ + strip_components: 1). VPS layout,
    service (perfops-site.service) and health port (3001) unchanged; trigger
    stays workflow_dispatch only.
  3. Pushes a branch and opens one draft PR on the monorepo.

Review fixes (from gemini-code-assist on #30)

  • harden.sh — branch-protection payload now passed as nested JSON via
    gh api --input - (flat key[sub]=... form is not expanded by gh and the
    endpoint 422s).
  • deploy-site.yml (generated) — RUNNER_TRACKING_ID="" before the background
    smoke server so the runner's process reaper doesn't kill it between steps.
  • collapse-consulting-site.sh & merge.sh — guard rm -rf "$WORKDIR"
    against empty / / / $HOME.

All scripts shellcheck-clean. Nothing is deleted or deployed by this PR — the
script never deletes; delete the source only after a green monorepo deploy.


Generated by Claude Code

muntianus added 3 commits May 30, 2026 13:53
…ocate prod deploy)

- WORKDIR guardrail before rm -rf (refuse empty / / / $HOME)
- RUNNER_TRACKING_ID="" so the background smoke server survives the step
gh api does not expand flat bracket-notation keys into nested JSON; the
branch-protection endpoint requires a nested body, so pass it on stdin.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request consolidates the perfops-consulting-site repository into the monorepo under site/, adds a manual deployment workflow, updates harden.sh to use a nested JSON body for branch protection API calls, and introduces WORKDIR guardrails in merge.sh. The review feedback identifies several critical issues in the newly generated workflow, including the use of non-existent GitHub Action versions (actions/checkout@v5 and actions/setup-node@v6), incomplete directory copying in appleboy/scp-action due to missing wildcards, and an unused variable. Additionally, it is recommended to expand the WORKDIR guardrails in both scripts to explicitly block relative paths like . and .. to prevent accidental deletions.

esac

- name: Checkout
uses: actions/checkout@v5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The action actions/checkout@v5 does not exist. The latest major version of actions/checkout is v4. Using a non-existent version will cause the workflow to fail immediately. Please downgrade to @v4.

Suggested change
uses: actions/checkout@v5
uses: actions/checkout@v4

run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

- name: Setup Node.js
uses: actions/setup-node@v6
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The action actions/setup-node@v6 does not exist. The latest major version of actions/setup-node is v4. Using a non-existent version will cause the workflow to fail immediately. Please downgrade to @v4.

Suggested change
uses: actions/setup-node@v6
uses: actions/setup-node@v4

working-directory: site
steps:
- name: Checkout tested commit
uses: actions/checkout@v5
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The action actions/checkout@v5 does not exist. The latest major version of actions/checkout is v4. Using a non-existent version will cause the workflow to fail immediately. Please downgrade to @v4.

Suggested change
uses: actions/checkout@v5
uses: actions/checkout@v4

port: ${{ secrets.VPS_PORT }}
# source paths are repo-root relative; strip the leading site/ so the
# VPS tree under target stays identical to the standalone-repo layout.
source: "site/app,site/components,site/data,site/deploy,site/lib,site/public,site/scripts,site/types,site/package.json,site/package-lock.json,site/next.config.ts,site/postcss.config.mjs,site/tsconfig.json,site/next-env.d.ts,site/eslint.config.mjs,site/proxy.ts,site/README.md,site/.env.example"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In appleboy/scp-action, specifying directory names directly (e.g., site/app) only copies the directory itself (often as an empty directory) rather than recursively copying its contents. To ensure all files and subdirectories are uploaded to the VPS, you should append /** to each directory path.

Suggested change
source: "site/app,site/components,site/data,site/deploy,site/lib,site/public,site/scripts,site/types,site/package.json,site/package-lock.json,site/next.config.ts,site/postcss.config.mjs,site/tsconfig.json,site/next-env.d.ts,site/eslint.config.mjs,site/proxy.ts,site/README.md,site/.env.example"
source: "site/app/**,site/components/**,site/data/**,site/deploy/**,site/lib/**,site/public/**,site/scripts/**,site/types/**,site/package.json,site/package-lock.json,site/next.config.ts,site/postcss.config.mjs,site/tsconfig.json,site/next-env.d.ts,site/eslint.config.mjs,site/proxy.ts,site/README.md,site/.env.example"


db="$(gh api "/repos/$OWNER/$SRC" --jq '.default_branch' 2>/dev/null || echo main)"
# Guardrail: never rm -rf an empty, root, or $HOME path (e.g. WORKDIR mis-set).
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The guardrail check for WORKDIR prevents dangerous deletions of / or $HOME, but it does not check for . or .. (or ./ and ../). If WORKDIR is accidentally set to . or .., rm -rf "$WORKDIR" will delete the current or parent directory, which can be disastrous. Consider expanding the guardrail to explicitly block these relative paths.

Suggested change
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ]; then
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ] || [ "$WORKDIR" = "." ] || [ "$WORKDIR" = ".." ] || [ "$WORKDIR" = "./" ] || [ "$WORKDIR" = "../" ]; then

HEALTH_RESULT="ok"
fi
BASE="${PROD_BASE_URL:-https://maslinka.ohbah.com:8443/}"
CONTRACT_PATHS="$(node scripts/ci/print-prod-smoke-paths.mjs | tr -d '\n')"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The variable CONTRACT_PATHS is defined by executing a Node script, but it is never used anywhere else in this step or the rest of the workflow. Consider either removing this line to avoid unnecessary execution or including the paths in the deploy summary.

Comment thread governance/operations/merge.sh Outdated

if [ "$APPLY" = "true" ]; then
# Guardrail: never rm -rf an empty, root, or $HOME path (e.g. WORKDIR mis-set).
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The guardrail check for WORKDIR prevents dangerous deletions of / or $HOME, but it does not check for . or .. (or ./ and ../). If WORKDIR is accidentally set to . or .., rm -rf "$WORKDIR" will delete the current or parent directory, which can be disastrous. Consider expanding the guardrail to explicitly block these relative paths.

Suggested change
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ]; then
if [ -z "${WORKDIR:-}" ] || [ "$WORKDIR" = "/" ] || [ "$WORKDIR" = "$HOME" ] || [ "$WORKDIR" = "." ] || [ "$WORKDIR" = ".." ] || [ "$WORKDIR" = "./" ] || [ "$WORKDIR" = "../" ]; then

muntianus added 2 commits May 30, 2026 13:59
…RACT_PATHS

Action versions (checkout@v5, setup-node@v6) and bare-dir scp source are kept:
both verified valid and copied as-is from the live prod-deploy workflow.
Copy link
Copy Markdown
Owner Author

Thanks @gemini-code-assist — addressed the review:

Applied

  • WORKDIR guard in collapse-consulting-site.sh and merge.sh now rejects "", /, ., .., ./, ../, $HOME (converted to a case).
  • Dropped the unused CONTRACT_PATHS (removed the needless node call too).

Not applied (verified false positives)

  • actions/checkout@v5 / actions/setup-node@v6 — these do exist (checkout v5.0.1, setup-node v6.2.0; confirmed via git ls-remote --tags). They're copied verbatim from the live standalone prod-deploy workflow, so downgrading to v4 would diverge from the proven prod baseline.
  • scp source: bare directory names — appleboy/scp-action copies directories recursively; the original standalone prod workflow uses the same bare-dir form and deploys successfully. Appending /** would deviate from that working baseline (and interacts awkwardly with strip_components).

This is a faithful relocation of an already-running prod workflow; trigger stays workflow_dispatch-only and the first manual run will validate it end-to-end.


Generated by Claude Code

@gemini-code-assist
Copy link
Copy Markdown

Thanks for the detailed update, @muntianus. The WORKDIR guardrail is a robust addition, and the explanation regarding the actions/ versions and scp behavior is clear. Given that this is a faithful relocation of a verified production workflow, the approach is sound. Good luck with the manual deployment and the subsequent cleanup.

@muntianus muntianus marked this pull request as ready for review May 30, 2026 16:20
@muntianus muntianus merged commit 99d3077 into main May 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant