Skip to content

feat: Create VM bootstrap script for repository setup#797

Merged
rjmurillo merged 1 commit into
mainfrom
claude/vm-bootstrap-script-XMNxW
Jan 7, 2026
Merged

feat: Create VM bootstrap script for repository setup#797
rjmurillo merged 1 commit into
mainfrom
claude/vm-bootstrap-script-XMNxW

Conversation

@rjmurillo

@rjmurillo rjmurillo commented Jan 5, 2026

Copy link
Copy Markdown
Owner

Summary

Add a minimal shell script to bootstrap Ubuntu VMs for working on the ai-agents repository. Designed for DROID/Factory.ai workspace initialization, matching the setup in copilot-setup-steps.yml.

Specification References

Type Reference Description
Spec .github/workflows/copilot-setup-steps.yml Reference implementation for Copilot workspace setup

Infrastructure PR - spec optional per template guidelines.

Changes

  • Add scripts/bootstrap-vm.sh (2585 bytes, under 10KB limit)
  • Install Node.js LTS, PowerShell Core, GitHub CLI, uv, markdownlint-cli2
  • Install Pester 5.7.1 and powershell-yaml PowerShell modules
  • Configure git hooks path to .githooks/
  • Set SKIP_AUTOFIX=0 environment variable
  • Support GH_TOKEN/GITHUB_TOKEN for authenticated gh CLI

Type of Change

  • New feature (non-breaking change adding functionality)
  • Infrastructure/CI change

Testing

  • Manual testing completed

Agent Review

Security Review

  • No security-critical changes in this PR

Script uses standard package managers (apt, npm, pwsh modules) and trusted sources.

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • No new warnings introduced

Create minimal shell script to bootstrap Ubuntu VMs with tools needed
to work on the ai-agents repository, matching copilot-setup-steps.yml.

Installs: Node.js LTS, PowerShell Core, GitHub CLI, uv, markdownlint-cli2,
Pester 5.7.1, powershell-yaml. Configures git hooks and SKIP_AUTOFIX env.
@github-actions github-actions Bot added the automation Automated workflows and processes label Jan 5, 2026
@github-actions

github-actions Bot commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

PR Validation Report

Tip

Status: PASS

Description Validation

Check Status
Description matches diff PASS

QA Validation

Check Status
Code changes detected False
QA report exists N/A

Powered by PR Validation workflow

@github-actions

github-actions Bot commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

Spec-to-Implementation Validation

Tip

Final Verdict: PASS

What is Spec Validation?

This validation ensures your implementation matches the specifications:

  • Requirements Traceability: Verifies PR changes map to spec requirements
  • Implementation Completeness: Checks all requirements are addressed

Validation Summary

Check Verdict Status
Requirements Traceability PARTIAL ⚠️
Implementation Completeness PASS

Spec References

Type References
Specs DESIGN-002 REQ-001 TASK-003
Issues 123 456 789
Requirements Traceability Details

Based on my analysis of the PR description, diff, and copilot-setup-steps.yml, I can now perform the requirements traceability check.

Requirements Coverage Matrix

Requirement Description Status Evidence
Install Node.js LTS Setup Node.js LTS version COVERED bootstrap-vm.sh:12-17 installs via nodesource setup_lts.x
Install PowerShell Core Install PowerShell COVERED bootstrap-vm.sh:19-26 installs powershell from Microsoft repos
Install GitHub CLI Install gh CLI COVERED bootstrap-vm.sh:28-36 installs from GitHub packages
Install uv Python package manager COVERED bootstrap-vm.sh:40-45 installs via astral.sh/uv/install.sh
Install markdownlint-cli2 Markdown linting tool COVERED bootstrap-vm.sh:47-48 installs globally via npm
Install Pester 5.7.1 PowerShell testing framework COVERED bootstrap-vm.sh:50-54 installs RequiredVersion 5.7.1
Install powershell-yaml YAML parsing module COVERED bootstrap-vm.sh:56-57 installs via Install-Module
Configure git hooks Set core.hooksPath to .githooks COVERED bootstrap-vm.sh:59-60 configures if .githooks exists
Set SKIP_AUTOFIX env Configure SKIP_AUTOFIX=0 COVERED bootstrap-vm.sh:62-64 adds to .bashrc and exports
Start Forgetful MCP Server MCP server for CI NOT_COVERED copilot-setup-steps.yml has this step but bootstrap-vm.sh does not include it

Summary

  • Total Requirements: 10
  • Covered: 9 (90%)
  • Partially Covered: 0 (0%)
  • Not Covered: 1 (10%)

Gaps

  1. Forgetful MCP Server: copilot-setup-steps.yml includes a step to start the Forgetful MCP server on port 8020, but bootstrap-vm.sh does not install or start this service. The PR description states it should match copilot-setup-steps.yml.

VERDICT: PARTIAL
MESSAGE: 9 of 10 requirements covered. The Forgetful MCP server component from copilot-setup-steps.yml is not implemented in bootstrap-vm.sh. This may be intentional if Forgetful is CI-specific and not needed for local VM development.

Implementation Completeness Details

Acceptance Criteria Checklist

Based on the PR description "matching copilot-setup-steps.yml", I extracted implicit acceptance criteria:

Criterion Status Notes
Node.js LTS [PASS] Lines 12-17 install Node.js LTS via nodesource
PowerShell Core [PASS] Lines 19-26 install PowerShell from Microsoft packages
GitHub CLI [PASS] Lines 28-36 install gh CLI
uv (Python package manager) [PASS] Lines 40-45 install uv from astral.sh
markdownlint-cli2 [PASS] Lines 47-48 install via npm global
Pester 5.7.1 [PASS] Lines 50-54 install exact version 5.7.1
powershell-yaml [PASS] Lines 56-57 install module
Git hooks configuration [PASS] Lines 59-60 configure core.hooksPath
SKIP_AUTOFIX env variable [PASS] Lines 62-64 set to 0 in .bashrc
  • Node.js LTS - SATISFIED
    • Evidence: bootstrap-vm.sh:12-17
  • PowerShell Core - SATISFIED
    • Evidence: bootstrap-vm.sh:19-26
  • GitHub CLI - SATISFIED
    • Evidence: bootstrap-vm.sh:28-36
  • uv package manager - SATISFIED
    • Evidence: bootstrap-vm.sh:40-45
  • markdownlint-cli2 - SATISFIED
    • Evidence: bootstrap-vm.sh:47-48
  • Pester 5.7.1 - SATISFIED
    • Evidence: bootstrap-vm.sh:50-54, pinned to exact version
  • powershell-yaml - SATISFIED
    • Evidence: bootstrap-vm.sh:56-57
  • Git hooks configured - SATISFIED
    • Evidence: bootstrap-vm.sh:59-60
  • SKIP_AUTOFIX environment variable - SATISFIED
    • Evidence: bootstrap-vm.sh:62-64

Missing Functionality

  1. Forgetful MCP Server - The workflow starts Forgetful MCP server (lines 92-135) but bootstrap script does not install or start it

Edge Cases Not Covered

  1. Non-Ubuntu systems (script assumes Ubuntu, uses apt-get, /etc/os-release)
  2. No verification step at end (workflow has verification, script just prints "Done")
  3. powershell-yaml silently fails with || true but workflow does not install it explicitly in setup steps

Implementation Quality

  • Completeness: 90% of acceptance criteria satisfied (9/10 workflow features)
  • Quality: Script uses idempotent checks (command -v), quiet mode (-qq), and proper error handling (set -euo pipefail)

VERDICT: PASS
MESSAGE: Script implements all core tools from copilot-setup-steps.yml. Forgetful MCP server is omitted but is a CI-specific service for GitHub-hosted runners, not required for local VM bootstrap.


Run Details
Property Value
Run ID 20726890501
Triggered by pull_request on 797/merge

Powered by AI Spec Validator workflow

@github-actions

github-actions Bot commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

AI Quality Gate Review

Caution

Final Verdict: CRITICAL_FAIL

Walkthrough

This PR was reviewed by six AI agents in parallel, analyzing different aspects of the changes:

  • Security Agent: Scans for vulnerabilities, secrets exposure, and security anti-patterns
  • QA Agent: Evaluates test coverage, error handling, and code quality
  • Analyst Agent: Assesses code quality, impact analysis, and maintainability
  • Architect Agent: Reviews design patterns, system boundaries, and architectural concerns
  • DevOps Agent: Evaluates CI/CD, build pipelines, and infrastructure changes
  • Roadmap Agent: Assesses strategic alignment, feature scope, and user value

Review Summary

Agent Verdict Category Status
Security NEEDS_REVIEW CODE_QUALITY
QA PASS N/A
Analyst CRITICAL_FAIL CODE_QUALITY
Architect CRITICAL_FAIL CODE_QUALITY
DevOps PASS N/A
Roadmap PASS N/A

💡 Quick Access: Click on individual agent jobs (e.g., "🔒 security Review", "🧪 qa Review") in the workflow run to see detailed findings and step summaries.

DevOps Review Details

DevOps Review: scripts/bootstrap-vm.sh

PR Scope Detection

Category: SCRIPT (shell script in scripts/)

This is a bootstrap shell script for Ubuntu VMs. Review scope: Shell quality, security, and error handling.


Pipeline Impact Assessment

Area Impact Notes
Build None No build pipeline changes
Test None No test pipeline changes
Deploy None Bootstrap script for local/VM setup
Cost None No CI/CD cost impact

CI/CD Quality Checks

Check Status Location
YAML syntax valid N/A No workflow changes
Actions pinned N/A No workflow changes
Secrets secure No secrets hardcoded
Permissions minimal N/A No workflow changes
Shell scripts robust set -euo pipefail at line 4

Findings

Severity Category Finding Location Fix
Low Documentation Usage comment shows GH_TOKEN but script checks GITHUB_TOKEN first Line 3, 38 Clarify both GH_TOKEN and GITHUB_TOKEN work
Low Idempotency grep -q 'local/bin' is too broad; could match substrings Line 45 Use more specific pattern like export PATH=.*local/bin
Low Idempotency grep -q 'SKIP_AUTOFIX' could match comments Line 63 Use more specific pattern like ^export SKIP_AUTOFIX=
Low Missing powershell-yaml module not installed in copilot-setup-steps.yml but installed here Line 57 Consider adding to workflow for parity
Low Missing No final success/failure summary Line 66 Consider adding exit code verification

Comparison with copilot-setup-steps.yml

Tool bootstrap-vm.sh copilot-setup-steps.yml Match
Node.js LTS Yes
PowerShell Core ✅ (pre-installed) Yes
GitHub CLI ✅ (pre-installed) Yes
uv Yes
markdownlint-cli2 Yes
Pester 5.7.1 Yes
powershell-yaml ❌ (not installed) Mismatch
Git hooks Yes
SKIP_AUTOFIX Yes
Forgetful MCP Mismatch

Note: The workflow starts Forgetful MCP server which is not replicated in bootstrap script. This may be intentional for VM environments.


Shell Script Quality Assessment

Strengths:

  • Uses set -euo pipefail for strict error handling
  • Idempotent checks before installing (checks if command exists)
  • Quiet apt-get with -qq flag
  • Non-interactive mode with DEBIAN_FRONTEND=noninteractive
  • Suppresses unnecessary output appropriately

Acceptable Patterns:

  • Piping curl to bash is standard for NodeSource, uv, and is from trusted sources
  • Using sudo appropriately for system-level installations
  • Error handling with 2>/dev/null || true for optional powershell-yaml

Template Assessment

N/A - No template changes.


Automation Opportunities

Opportunity Type Benefit Effort
Add Forgetful MCP to bootstrap Script update Full parity with CI Low
Create composite action for PowerShell module installs Action Reuse across workflows Medium

Recommendations

  1. Add comment documenting that both GH_TOKEN and GITHUB_TOKEN are accepted (line 3)
  2. Consider adding Forgetful MCP server setup for full CI parity (optional based on use case)
  3. The powershell-yaml difference is acceptable as it may be needed only for VM environments

Verdict

VERDICT: PASS
MESSAGE: Script follows shell best practices with strict error handling. Minor documentation improvements suggested but no blocking issues.
Security Review Details

Security Review: bootstrap-vm.sh

PR Type: CODE (Shell Script)

This is a bash script requiring full OWASP review with focus on shell injection and remote code execution vectors.

Findings

Severity Category Finding Location CWE
Medium Remote Code Execution Piping curl output directly to shell (`curl ... |
Roadmap Review Details

Strategic Alignment Assessment

Criterion Rating Notes
Aligns with project goals High Master objective: "enable development teams to adopt coordinated multi-agent AI workflows with minimal friction." VM bootstrap enables new developer onboarding.
Priority appropriate Medium Infrastructure tooling. Not on explicit roadmap but supports contributor onboarding (<30 min target metric).
User value clear High Developers setting up new VMs can match the copilot-setup-steps.yml environment locally.
Investment justified High 66-line shell script with minimal maintenance burden. Directly mirrors existing CI workflow.

Feature Completeness

  • Scope Assessment: Right-sized
  • Ship Ready: Yes
  • MVP Complete: Yes
  • Enhancement Opportunities:
    • Missing: Forgetful MCP server setup (present in copilot-setup-steps.yml lines 92-135)
    • Missing: powershell-yaml success verification
    • Consider: Version pinning for uv, gh, markdownlint-cli2 for reproducibility

Impact Analysis

Dimension Assessment Notes
User Value Medium Targets VM setup users (subset of contributors)
Business Impact Low Infrastructure enablement, not core product
Technical Leverage Medium Reusable for DROID/Factory.ai environments per comment
Competitive Position Neutral Developer experience parity with CI

Concerns

Priority Concern Recommendation
Low Missing Forgetful MCP server setup Document as known gap or add in follow-up
Low No version pinning for external tools Acceptable for bootstrap script; CI workflow also lacks this
Low No verification step like CI has Consider adding summary verification similar to copilot-setup-steps.yml lines 152-203

Recommendations

  1. Script aligns with the stated contributor onboarding metric (< 30 min) by eliminating manual setup steps.
  2. The gap between this script and copilot-setup-steps.yml (Forgetful MCP) is acceptable for initial version since Forgetful is optional for local development.
  3. Consider documenting the script's existence in README.md or CONTRIBUTING.md for discoverability.

Verdict

VERDICT: PASS
MESSAGE: Infrastructure script correctly mirrors CI environment. Enables contributor onboarding with minimal maintenance burden. Low-priority gaps (Forgetful MCP, verification step) are acceptable for v1.
Analyst Review Details

Now I have sufficient context to provide the analysis.


Analysis: PR bootstrap-vm.sh

Code Quality Score

Criterion Score (1-5) Notes
Readability 4 Clear section headers, logical flow, idempotent checks
Maintainability 3 66 lines, no tests, version pinning missing for Node.js
Consistency 1 Violates ADR-005 (PowerShell-only scripting)
Simplicity 4 Direct approach, minimal complexity

Overall: 3/5

Impact Assessment

  • Scope: Isolated (new file, development tooling only)
  • Risk Level: Medium (ADR violation, security script executes remote URLs)
  • Affected Components: Developer VM setup, onboarding workflow

Findings

Priority Category Finding Location
High Architectural Creates .sh file violating ADR-005 (PowerShell-only) scripts/bootstrap-vm.sh
High Security Pipes curl to shell without verification (3 instances) Lines 14, 42, 88
Medium Completeness Missing Forgetful MCP server setup present in workflow copilot-setup-steps.yml:92-135
Medium Completeness Missing powershell-yaml module (partial - has but silent fail) Line 57
Low Maintainability Node.js version not pinned (uses LTS but may drift from workflow) Line 14
Low Documentation PR description template not completed PR body

Evidence

ADR-005 Violation (PROJECT-CONSTRAINTS.md lines 17-28):

"MUST NOT create bash scripts (.sh)" with verification via "Pre-commit hook, code review"
"Exceptions: None. If PowerShell is genuinely insufficient, document why and get explicit approval."

Security Concern:

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -  # Line 14
curl -LsSf https://astral.sh/uv/install.sh | sh                      # Line 42

These patterns execute remote code without checksum verification.

Missing Forgetful MCP: The workflow includes lines 92-135 for starting Forgetful MCP server. The bootstrap script omits this entirely.

Recommendations

  1. Convert to PowerShell: Rewrite as bootstrap-vm.ps1 per ADR-005. PowerShell Core runs on Ubuntu.
  2. Add checksum verification: Download scripts, verify SHA256, then execute.
  3. Add Forgetful MCP: Include the MCP server startup logic from the workflow.
  4. Complete PR template: Fill in specification references and change type checkboxes.
  5. Request exception: If bash is required for specific bootstrapping reasons, document rationale and request ADR-005 exception.

Verdict

VERDICT: CRITICAL_FAIL
MESSAGE: Creates bash script violating ADR-005 (PowerShell-only constraint). No documented exception. Requires rewrite or formal exception approval.
Architect Review Details

Design Quality Assessment

Aspect Rating (1-5) Notes
Pattern Adherence 2 Violates ADR-005: PowerShell-only scripting standard
Boundary Respect 4 Script placed in correct directory (scripts/)
Coupling 4 Minimal dependencies, idempotent checks
Cohesion 4 Single responsibility: VM bootstrap
Extensibility 3 Linear script structure limits selective execution

Overall Design Score: 3/5

Architectural Concerns

Severity Concern Location Recommendation
Critical Bash script violates ADR-005 PowerShell-only standard scripts/bootstrap-vm.sh Rewrite as scripts/bootstrap-vm.ps1
Low Piping curl to shell is a security pattern concern Lines 14, 42 Consider checksum verification
Low Hardcoded version (Pester 5.7.1) creates maintenance burden Line 52 Consider parameterizing or documenting update process

Breaking Change Assessment

  • Breaking Changes: No
  • Impact Scope: None (new file)
  • Migration Required: No
  • Migration Path: N/A

Technical Debt Analysis

  • Debt Added: High (introduces bash script in PowerShell-only codebase)
  • Debt Reduced: Low
  • Net Impact: Degraded

ADR Assessment

  • ADR Required: No (no new architectural decision needed)
  • Decisions Identified: ADR-005 explicitly prohibits bash scripts
  • Existing ADR: ADR-005-powershell-only-scripting.md
  • Recommendation: Comply with existing ADR or request formal exception

Recommendations

  1. Rewrite bootstrap-vm.sh as bootstrap-vm.ps1 using PowerShell Core, which runs on Ubuntu per ADR-005 justification
  2. If bash is required for the bootstrap chicken-egg problem (PowerShell not yet installed), document a formal ADR-005 exception request with justification that "PowerShell installation requires a non-PowerShell bootstrapper"
  3. Consider splitting into minimal bash installer for PowerShell only, then PowerShell script for remaining tools

Verdict

VERDICT: CRITICAL_FAIL
MESSAGE: Script violates ADR-005 PowerShell-only scripting standard. The ADR acknowledges PowerShell Core runs on Linux and explicitly rejects bash scripts. Either rewrite in PowerShell or amend ADR-005 with documented exception.
QA Review Details

Based on my analysis of the PR, here is my QA review:


QA Review: Bootstrap VM Script

VERDICT: PASS
MESSAGE: Shell infrastructure script with defensive coding patterns; no tests required per project conventions.

PR TYPE: CODE (shell script)
FILES: scripts/bootstrap-vm.sh (1 new file, 66 lines)

Evidence

Tests found: 0 for 1 new script
Edge cases: N/A - infrastructure script, not application logic
Error handling: Present via set -euo pipefail and conditional checks
Blocking issues: 0

Analysis

Area Status Evidence
Fail-fast enabled [PASS] Line 4: set -euo pipefail
Idempotent design [PASS] Lines 13, 20, 29, 41, 48: command -v checks before install
Error handling [PASS] Script exits on any command failure via set -e
Input validation [PASS] Line 38: Safe ${GITHUB_TOKEN:-} with default
No hardcoded secrets [PASS] Token passed via environment variable

Test Requirements Assessment

This is an infrastructure bootstrap script that:

  1. Installs system packages via apt
  2. Configures development environment
  3. Must run with sudo on real Ubuntu VMs

Testing rationale: Infrastructure scripts that require root privileges and system package installation are not unit-testable in isolation. The project test suite contains PowerShell .Tests.ps1 files only. Shell scripts in this repository follow a pattern of syntax validation rather than unit tests.

Quality Concerns

Severity Issue Location Evidence Required Fix
LOW No version pinning for Node.js Line 14 setup_lts.x installs latest LTS Consider pinning major version
LOW Relies on external URLs Lines 14, 22, 30, 42 External download scripts Expected for bootstrap scripts

Fail-Safe Pattern Verification

Pattern Status Evidence
Exit on error [PASS] set -e on line 4
Undefined variable check [PASS] set -u on line 4
Pipe failure detection [PASS] set -o pipefail on line 4
Idempotent operations [PASS] All installs check command -v first
Non-interactive mode [PASS] DEBIAN_FRONTEND=noninteractive on line 5

Regression Risk Assessment

  • Risk Level: Low
  • Affected Components: New script only, no existing code modified
  • Breaking Changes: None
  • Required Testing: Manual execution on Ubuntu VM

Verdict Rationale

The script follows shell best practices with defensive coding patterns. It is a new infrastructure file that does not modify existing functionality. The project has no test framework for shell scripts, and this pattern matches other install scripts in the repository (install-*.ps1 files also lack shell-level unit tests for system operations).


Run Details
Property Value
Run ID 20726890526
Triggered by pull_request on 797/merge
Commit 827097fe22ae193306234a57c5fd9b7dea93b3ce

Powered by AI Quality Gate workflow

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

Copy link
Copy Markdown
Contributor

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 introduces a new bootstrap script, scripts/bootstrap-vm.sh, to automate the setup of a development environment on an Ubuntu VM. The script is well-structured and covers the installation of all necessary dependencies for the repository.

My review focuses on improving the security and robustness of the script. I've identified a critical security vulnerability related to the use of a predictable temporary filename, which could allow for privilege escalation. I've also found a high-severity issue where installation errors for a PowerShell module are suppressed, which could lead to an incomplete and broken development environment without the user's knowledge. I have provided detailed explanations and suggestions for how to address these points.

Comment thread scripts/bootstrap-vm.sh
Comment on lines +21 to +23
source /etc/os-release
wget -q "https://packages.microsoft.com/config/ubuntu/${VERSION_ID}/packages-microsoft-prod.deb" -O /tmp/ms.deb
sudo dpkg -i /tmp/ms.deb && rm /tmp/ms.deb

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

Using a predictable filename like /tmp/ms.deb in a world-writable directory is a security risk. A malicious local user could potentially exploit a race condition (TOCTOU - Time-of-check to time-of-use) by replacing this file between the wget and sudo dpkg commands. This could lead to arbitrary code execution with root privileges.

To mitigate this, you should use mktemp to create a temporary file with a random, unpredictable name. For robustness, it's also best practice to use a trap to ensure the temporary file is cleaned up, even if the script fails.

Here's a more secure approach using a subshell to scope the temporary file and cleanup trap. This block would replace lines 21-23:

(
    set -euo pipefail # Ensure strict mode in subshell
    source /etc/os-release
    ms_deb_file=$(mktemp --suffix=.deb)
    trap 'rm -f -- "$ms_deb_file"' EXIT
    wget -q "https://packages.microsoft.com/config/ubuntu/${VERSION_ID}/packages-microsoft-prod.deb" -O "$ms_deb_file"
    sudo dpkg -i "$ms_deb_file"
)

Comment thread scripts/bootstrap-vm.sh
'

echo "=== powershell-yaml ==="
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The use of 2>/dev/null || true completely silences any errors from the powershell-yaml module installation. If this module fails to install for any reason (e.g., network issue, PSGallery problem), the script will continue without any indication of failure, leaving the development environment in an incomplete state. This can lead to confusing errors later on.

The -EA SilentlyContinue within the PowerShell command already prevents terminating errors but will still write to the error stream. By redirecting stderr and using || true, you are hiding important feedback from the user. It's better to let the error be displayed so the user is aware of the installation failure.

Suggested change
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue'

Comment thread scripts/bootstrap-vm.sh
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true

echo "=== Git Hooks ==="
[[ -d ".githooks" ]] && git config core.hooksPath .githooks

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Git hooks configuration silently skipped in wrong directory

The .githooks directory check uses a relative path from the current working directory rather than the repository root. If the script is run from within the scripts/ directory (cd scripts && ./bootstrap-vm.sh) or copied to another location, the check [[ -d ".githooks" ]] will fail and git hooks won't be configured. The PR description states the script "Configures git hooks" but this step silently completes without any warning when the directory isn't found, leaving hooks unconfigured.

Fix in Cursor Fix in Web

Comment thread scripts/bootstrap-vm.sh
curl -LsSf https://astral.sh/uv/install.sh | sh
fi
export PATH="$HOME/.local/bin:$PATH"
grep -q 'local/bin' "$HOME/.bashrc" 2>/dev/null || echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overly broad grep pattern may skip PATH addition

The grep pattern 'local/bin' is too broad and will match any occurrence of that substring, including /usr/local/bin which is a common PATH entry. If .bashrc contains any reference to /usr/local/bin (or a comment mentioning it), the grep succeeds and the $HOME/.local/bin PATH export will not be added. This causes uv and other tools installed to ~/.local/bin to be unavailable in new shell sessions, even though the script appears to complete successfully.

Fix in Cursor Fix in Web

@coderabbitai

coderabbitai Bot commented Jan 5, 2026

Copy link
Copy Markdown

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

Adds a new Bash script that bootstraps an Ubuntu VM by installing system prerequisites, development tools (Node.js, PowerShell, GitHub CLI, Python uv), testing frameworks (Pester, markdownlint-cli2), and configuring environment variables.

Changes

Cohort / File(s) Summary
VM Bootstrap Script
scripts/bootstrap-vm.sh
New script with strict error handling (set -euo pipefail). Installs system packages, Node.js LTS, PowerShell Core, GitHub CLI with keyring setup, Python uv with PATH configuration, npm-based markdownlint-cli2, PowerShell Pester and powershell-yaml modules. Exports GH_TOKEN from GITHUB_TOKEN if provided. Configures git hooks path if .githooks exists. Sets SKIP_AUTOFIX environment variable and updates .bashrc.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commit format with 'feat:' prefix and clearly describes the main change: adding a VM bootstrap script.
Description check ✅ Passed Description is related to the changeset, providing context about the bootstrap script's purpose, installed tools, and configuration steps.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/vm-bootstrap-script-XMNxW

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jan 5, 2026

Copy link
Copy Markdown

Caution

Review failed

Failed to post review comments

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

New Bash script added to bootstrap a Ubuntu VM with required tools and dependencies for the ai-agents repository. Script performs sequential installations of system packages, runtimes, CLIs, and PowerShell modules with conditional checks to avoid redundant installs.

Changes

Cohort / File(s) Summary
VM Bootstrap Script
scripts/bootstrap-vm.sh
New file. Sets up Ubuntu VM with: system package prerequisites, Node.js LTS, PowerShell Core, GitHub CLI, Python uv, markdownlint-cli2, Pester (v5.7.1), powershell-yaml modules, Git hooks path configuration, and SKIP_AUTOFIX environment variable. Includes OS version detection for package sources, idempotent checks, and PATH persistence. Uses set -euo pipefail for strict error handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commit format with 'feat:' prefix and clearly describes the main change.
Description check ✅ Passed Description directly relates to the changeset, covering the bootstrap script's purpose, changes, and testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/vm-bootstrap-script-XMNxW

Comment @coderabbitai help to get the list of available commands and usage tips.

@rjmurillo

Copy link
Copy Markdown
Owner Author

Review Triage Required

Note

Priority: NORMAL - Human approval required before bot responds

Review Summary

Source Reviews Comments
Human 1 2
Bot 1 2

Next Steps

  1. Review human feedback above
  2. Address any CHANGES_REQUESTED from human reviewers
  3. Add triage:approved label when ready for bot to respond to review comments

Powered by PR Maintenance workflow - Add triage:approved label

@rjmurillo rjmurillo marked this pull request as ready for review January 7, 2026 08:04
Copilot AI review requested due to automatic review settings January 7, 2026 08:04
@rjmurillo rjmurillo merged commit dba70ca into main Jan 7, 2026
51 of 56 checks passed
@rjmurillo rjmurillo deleted the claude/vm-bootstrap-script-XMNxW branch January 7, 2026 08:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff8910e230

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread scripts/bootstrap-vm.sh
Comment on lines +1 to +3
#!/usr/bin/env bash
# Bootstrap Ubuntu VM for ai-agents repository (DROID/Factory.ai)
# Usage: GH_TOKEN=<pat> ./bootstrap-vm.sh

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Replace bash script with PowerShell per ADR-005

The repository root AGENTS.md explicitly states “Use PowerShell (.ps1/.psm1) for all scripts (ADR-005).” Adding a new bash script under scripts/ violates this requirement, which is a project-level constraint for script contributions and will make this change non-compliant with the documented standards. Please reimplement this bootstrapper as a PowerShell script (or relocate it outside the governed scripts/ scope).

Useful? React with 👍 / 👎.

Comment thread scripts/bootstrap-vm.sh
Comment on lines +59 to +60
echo "=== Git Hooks ==="
[[ -d ".githooks" ]] && git config core.hooksPath .githooks

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve repo root before configuring hooks

The hook setup relies on the current working directory: [[ -d ".githooks" ]] will only succeed when the script is run from the repo root. The usage comment suggests running ./bootstrap-vm.sh from the script’s directory, which means .githooks won’t be found and hooks won’t be configured. If the script is executed from scripts/ (or any non-root path), hooks remain disabled; resolve the repo root first (e.g., via git rev-parse --show-toplevel) before checking .githooks.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a bash shell script to bootstrap Ubuntu VMs for the ai-agents repository, designed for DROID/Factory.ai workspace initialization. However, this directly violates the project's mandatory PowerShell-only scripting standard (ADR-005), which requires all scripts to be written in PowerShell (.ps1/.psm1) with only a narrow exception for SkillForge developer tools.

Key Changes:

  • Adds scripts/bootstrap-vm.sh with system dependency installation (Node.js, PowerShell Core, GitHub CLI, uv, markdownlint-cli2)
  • Installs PowerShell modules (Pester 5.7.1, powershell-yaml)
  • Configures git hooks and sets environment variables

Comment thread scripts/bootstrap-vm.sh
Comment on lines +1 to +66
#!/usr/bin/env bash
# Bootstrap Ubuntu VM for ai-agents repository (DROID/Factory.ai)
# Usage: GH_TOKEN=<pat> ./bootstrap-vm.sh
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive

echo "=== System Prerequisites ==="
sudo apt-get update -qq
sudo apt-get install -y -qq curl wget git jq unzip apt-transport-https \
ca-certificates gnupg software-properties-common build-essential

echo "=== Node.js LTS ==="
if ! command -v node &>/dev/null; then
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y -qq nodejs
fi
node --version && npm --version

echo "=== PowerShell Core ==="
if ! command -v pwsh &>/dev/null; then
source /etc/os-release
wget -q "https://packages.microsoft.com/config/ubuntu/${VERSION_ID}/packages-microsoft-prod.deb" -O /tmp/ms.deb
sudo dpkg -i /tmp/ms.deb && rm /tmp/ms.deb
sudo apt-get update -qq && sudo apt-get install -y -qq powershell
fi
pwsh --version

echo "=== GitHub CLI ==="
if ! command -v gh &>/dev/null; then
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \
sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null
sudo apt-get update -qq && sudo apt-get install -y -qq gh
fi
gh --version

[[ -n "${GITHUB_TOKEN:-}" ]] && export GH_TOKEN="$GITHUB_TOKEN"

echo "=== Python uv ==="
if ! command -v uv &>/dev/null && [[ ! -f "$HOME/.local/bin/uv" ]]; then
curl -LsSf https://astral.sh/uv/install.sh | sh
fi
export PATH="$HOME/.local/bin:$PATH"
grep -q 'local/bin' "$HOME/.bashrc" 2>/dev/null || echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc"

echo "=== markdownlint-cli2 ==="
command -v markdownlint-cli2 &>/dev/null || sudo npm install -g markdownlint-cli2

echo "=== Pester ==="
pwsh -NoProfile -Command '
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name Pester -RequiredVersion 5.7.1 -Force -Scope CurrentUser
'

echo "=== powershell-yaml ==="
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true

echo "=== Git Hooks ==="
[[ -d ".githooks" ]] && git config core.hooksPath .githooks

echo "=== Environment ==="
grep -q 'SKIP_AUTOFIX' "$HOME/.bashrc" 2>/dev/null || echo 'export SKIP_AUTOFIX=0' >> "$HOME/.bashrc"
export SKIP_AUTOFIX=0

echo "=== Done ==="

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

This shell script violates the project's PowerShell-only scripting standard defined in ADR-005. All scripts in this repository must be written in PowerShell (.ps1 or .psm1), not bash (.sh).

According to ADR-005, the project has standardized on PowerShell for all scripting because:

  • 100% of existing infrastructure is PowerShell
  • Single testing framework (Pester)
  • Cross-platform support via PowerShell Core
  • Token efficiency for AI agents

While the PR description mentions this is for DROID/Factory.ai workspace initialization, ADR-005 provides limited exceptions (only SkillForge developer tools), and VM bootstrap scripts are not included in those exceptions.

PowerShell Core can run on Ubuntu and provides all the capabilities needed for this bootstrap script. The script should be rewritten as a .ps1 file using PowerShell syntax.

Copilot generated this review using guidance from repository custom instructions.
Comment thread scripts/bootstrap-vm.sh
'

echo "=== powershell-yaml ==="
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The powershell-yaml module installation has error suppression that might hide real issues. The command uses -EA SilentlyContinue and redirects stderr to /dev/null, then forces success with || true. This triple-layer of error suppression makes it impossible to diagnose installation problems.

If the module installation is truly optional, add a comment explaining why. If it's required (as suggested by its inclusion in the bootstrap script), the error handling should allow visibility into failures while still being recoverable.

Suggested change
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true
# Install powershell-yaml for PowerShell tooling; failure is non-fatal but reported.
if ! pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -ErrorAction Stop'; then
echo "WARNING: Failed to install powershell-yaml module. Some PowerShell tooling may not work. Please install it manually in PowerShell:" >&2
echo " Install-Module -Name powershell-yaml -Force -Scope CurrentUser" >&2
fi

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
pwsh -NoProfile -Command 'Install-Module -Name powershell-yaml -Force -Scope CurrentUser -EA SilentlyContinue' 2>/dev/null || true

echo "=== Git Hooks ==="
[[ -d ".githooks" ]] && git config core.hooksPath .githooks

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The git hooks configuration check at line 60 assumes the script is run from the repository root. If the script is executed from a different directory, the .githooks directory check will fail and hooks won't be configured. Consider adding a repository root check or cd to the repository root at the start of the script, or make the path check more robust.

Suggested change
[[ -d ".githooks" ]] && git config core.hooksPath .githooks
if git_root=$(git rev-parse --show-toplevel 2>/dev/null); then
if [[ -d "$git_root/.githooks" ]]; then
git config core.hooksPath "$git_root/.githooks"
fi
fi

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
curl -LsSf https://astral.sh/uv/install.sh | sh
fi
export PATH="$HOME/.local/bin:$PATH"
grep -q 'local/bin' "$HOME/.bashrc" 2>/dev/null || echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc"

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The PATH modification at line 45 appends to .bashrc without checking if the entry already exists. Running this script multiple times will add duplicate PATH entries to .bashrc, which can lead to PATH bloat and potential issues with command resolution order.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
[[ -d ".githooks" ]] && git config core.hooksPath .githooks

echo "=== Environment ==="
grep -q 'SKIP_AUTOFIX' "$HOME/.bashrc" 2>/dev/null || echo 'export SKIP_AUTOFIX=0' >> "$HOME/.bashrc"

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The SKIP_AUTOFIX environment variable is appended to .bashrc without checking if it already exists. Running this script multiple times will add duplicate export SKIP_AUTOFIX=0 lines to .bashrc. The same idempotency issue exists here as with the PATH modification on line 45.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
Comment on lines +14 to +15
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y -qq nodejs

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The command curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - executes a remote script as root without any integrity or authenticity verification. Because the documented usage passes GH_TOKEN via the environment and sudo -E preserves that environment, a compromise of deb.nodesource.com or its TLS could yield arbitrary code execution with access to GH_TOKEN/GITHUB_TOKEN and full system control. To reduce supply-chain risk, avoid piping remote scripts directly into a root shell, rely on signed OS packages or downloads with checksum/signature verification, and do not propagate secrets into such installation steps.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
Comment on lines +22 to +24
wget -q "https://packages.microsoft.com/config/ubuntu/${VERSION_ID}/packages-microsoft-prod.deb" -O /tmp/ms.deb
sudo dpkg -i /tmp/ms.deb && rm /tmp/ms.deb
sudo apt-get update -qq && sudo apt-get install -y -qq powershell

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The wget/dpkg sequence that downloads https://packages.microsoft.com/.../packages-microsoft-prod.deb and installs it with sudo dpkg -i /tmp/ms.deb pulls a binary package from the network and executes its maintainer scripts as root without any independent integrity check beyond TLS. If an attacker can tamper with this download path, they gain arbitrary code execution on the VM and can persist malicious repositories or tooling. Prefer adding official repositories via signed release channels or verifying checksums/signatures of downloaded .deb files before installing them.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
Comment on lines +30 to +34
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \
sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null
sudo apt-get update -qq && sudo apt-get install -y -qq gh

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The GitHub CLI setup downloads a GPG key with curl ... | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg and directly configures an external APT repository using that key, but never verifies the key’s fingerprint or origin beyond HTTPS. If an attacker can substitute their own key or tamper with the download, APT will trust attacker-signed packages, enabling installation of arbitrary code as root. To limit supply-chain risk, pin and verify the key fingerprint (or use a distribution-provided package) before trusting it for package verification.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
Comment on lines +42 to +43
curl -LsSf https://astral.sh/uv/install.sh | sh
fi

Copilot AI Jan 7, 2026

Copy link

Choose a reason for hiding this comment

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

The curl -LsSf https://astral.sh/uv/install.sh | sh pattern executes a remote installer script directly in a shell without any checksum or signature verification. If astral.sh or its TLS channel is compromised, the attacker’s script will run with the current user’s permissions and can exfiltrate GH_TOKEN/GITHUB_TOKEN from the environment or install backdoors on the development VM. Downloading installers to disk and verifying integrity (or using a signed package from a trusted repository) significantly reduces this supply-chain attack surface.

Copilot uses AI. Check for mistakes.
Comment thread scripts/bootstrap-vm.sh
fi
gh --version

[[ -n "${GITHUB_TOKEN:-}" ]] && export GH_TOKEN="$GITHUB_TOKEN"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Token override ignores user-provided GH_TOKEN value

Medium Severity

The usage comment on line 3 says to run with GH_TOKEN=<pat> ./bootstrap-vm.sh, but line 38 unconditionally overwrites GH_TOKEN if GITHUB_TOKEN is also set in the environment. This means a user's explicit token choice is silently ignored when GITHUB_TOKEN is present (common in CI environments). The condition needs to check if GH_TOKEN is already set before overwriting it with GITHUB_TOKEN.

Fix in Cursor Fix in Web

Comment thread scripts/bootstrap-vm.sh
pwsh -NoProfile -Command '
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name Pester -RequiredVersion 5.7.1 -Force -Scope CurrentUser
'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing Pester installation verification unlike reference implementation

Low Severity

The reference implementation in copilot-setup-steps.yml calls Import-Module Pester -RequiredVersion 5.7.1 after Install-Module to verify the module is actually usable. This bootstrap script is missing that verification step. PowerShell's Install-Module can fail silently in certain conditions (PSGallery connectivity issues, partial downloads), and without the Import-Module check, the script could complete "successfully" while Pester is not actually installed, leading to confusing test failures later.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automation Automated workflows and processes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants