Skip to content
Merged
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
26 changes: 26 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
reviews:
profile: assertive
path_instructions:
- path: "**/vendor_files/**"
instructions: "These files came from a vendor and we're not allowed to change them. Refer to it if you need to understand how the main code interacts with it, but do not make comments about it."
tools:
eslint: # when the code contains typescript, eslint will be run by pre-commit, and coderabbit often generates false positives
enabled: false
ruff: # when the code contains python, ruff will be run by pre-commit, and coderabbit often generates false positives
enabled: false
pylint: # when the code contains python, pylint will be run by pre-commit, and coderabbit often generates false positives
enabled: false
flake8: # we use ruff instead (when we use Python)
enabled: false
poem: false
# the commit status is driven by our repository config and required checks, we don't want CodeRabbit messing with it
commit_status: false
auto_review:
# a main purpose of opening a draft PR might be to get CodeRabbit feedback early
drafts: true
finishing_touches:
docstrings:
enabled: false # if we wanted AI to generate docstrings, it would be via CLI, not in the GitHub interface
unit_tests:
enabled: false # Quis custodiet ipsos custodes? not something we want AI doing, especially not via the GitHub interface
18 changes: 18 additions & 0 deletions .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Changes here will be overwritten by Copier
_commit: v0.0.91
_src_path: gh:LabAutomationAndScreening/copier-base-template.git
description: Creating libraries in the VueJS ecosystem
install_claude_cli: false
python_ci_versions:
- 3.13.2
python_version: 3.13.2
repo_name: copier-vue-package-template
repo_org_name: LabAutomationAndScreening
repo_org_name_for_copyright: LabAutomationAndScreening
ssh_port_number: 51211
template_might_want_to_install_aws_ssm_port_forwarding_plugin: false
template_uses_javascript: true
template_uses_pulumi: false
template_uses_python: false
template_uses_vuejs: true

Comment on lines +17 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Trailing blank line violates YAMLlint configuration.

Static analysis flags an extra blank line at the end of the file. Remove the trailing blank line to comply with the linting rules.

🔎 Proposed fix
 template_uses_vuejs: true
-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template_uses_vuejs: true
template_uses_vuejs: true
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 18-18: too many blank lines (1 > 0)

(empty-lines)

🤖 Prompt for AI Agents
.copier-answers.yml around lines 17 to 18: the file currently ends with a
trailing blank line which violates YAMLlint; remove the extra blank line so the
file ends immediately after the last YAML entry ("template_uses_vuejs: true")
with no additional empty line or whitespace at EOF, then re-run lint to confirm
the violation is resolved.

22 changes: 22 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# base image tags available at https://mcr.microsoft.com/v2/devcontainers/universal/tags/list
# added the platform flag to override any local settings since this image is only compatible with linux/amd64. since this image is only x64 compatible, suppressing the hadolint rule
# hadolint ignore=DL3029
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/universal:2.13.1-focal

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

RUN apt-get update -y && apt-get install -y \
"bash-completion=$(apt-cache madison bash-completion | awk '{print $3}' | grep '^1:2.10' | head -n 1)" --no-install-recommends \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Create the venv folder and set permissions for anyone to modify---this is necessary to be able to break out the venv folder as a separate docker volume for better performance on Windows hosts
ARG REPO_NAME=copier-base-template
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if REPO_NAME is used as a template variable in copier configuration
rg -n "REPO_NAME|repo_name" --type=yaml --type=jinja -C3

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 1259


🏁 Script executed:

#!/bin/bash
# Also check for copier config files directly
fd -type f -name "copier.yml" -o -name "copier.yaml" -o -name ".copier*" | head -20

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Check the repository name from git or README
git config --get remote.origin.url 2>/dev/null || echo "No git origin found"
if [ -f README.md ]; then head -20 README.md; fi

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 2437


🏁 Script executed:

#!/bin/bash
# Check the full Dockerfile to see how REPO_NAME is used
cat -n .devcontainer/Dockerfile | head -40

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 1358


🏁 Script executed:

#!/bin/bash
# Search for all REPO_NAME usage in the codebase
rg -n "REPO_NAME" -C2

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 79


🏁 Script executed:

#!/bin/bash
# Check if there's a reference to copier-base-template anywhere
rg -n "copier-base-template|base-template" -C2

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 1714


🏁 Script executed:

#!/bin/bash
# Check if devcontainer.json or other configs pass REPO_NAME as build arg
fd -type f -name "devcontainer.json" | xargs cat 2>/dev/null

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Check git history to see if this Dockerfile was copied from base-template
git log --oneline .devcontainer/Dockerfile | head -10

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Find and check devcontainer.json files for build args
find . -name "devcontainer.json" -type f -exec cat {} \;

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 2732


🏁 Script executed:

#!/bin/bash
# Check if REPO_NAME is referenced in any build context or docker compose
rg "build.*args|ARG REPO_NAME|REPO_NAME" --type json -C3

Repository: LabAutomationAndScreening/copier-vue-package-template

Length of output: 79


Update REPO_NAME default to match the template variable or use Jinja substitution.

The default REPO_NAME=copier-base-template (line 14) should either be changed to copier-vue-package-template or, more appropriately, should use the copier template variable: ARG REPO_NAME={{ repo_name }}. This ensures the venv path (used in line 15) correctly reflects the actual repository name when the template is instantiated.

🤖 Prompt for AI Agents
In .devcontainer/Dockerfile around line 14, the ARG REPO_NAME default is
incorrect; update it to use the copier template variable or set the correct
template name so the venv path resolves properly. Replace the current line with
an argument that uses Jinja substitution (ARG REPO_NAME={{ repo_name }}) or, if
you prefer a concrete default, set ARG REPO_NAME=copier-vue-package-template;
ensure any subsequent references (like the venv path on the next line) rely on
this ARG.

ENV VENV_PATH=/workspaces/${REPO_NAME}/.venv
RUN mkdir -p /workspace && \
mkdir -p ${VENV_PATH} && \
chmod -R 777 /workspaces ${VENV_PATH} && \
chgrp -R 0 /workspaces ${VENV_PATH}
Comment on lines +16 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix path inconsistency: /workspace vs /workspaces.

Line 16 creates /workspace (singular), but the VENV_PATH on line 15 references /workspaces (plural), and lines 18-19 set permissions on /workspaces. This inconsistency may cause the venv directory creation to fail.

🔎 Proposed fix
-RUN mkdir -p /workspace && \
+RUN mkdir -p /workspaces && \
     mkdir -p ${VENV_PATH} && \
     chmod -R 777 /workspaces ${VENV_PATH} && \
     chgrp -R 0 /workspaces ${VENV_PATH}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RUN mkdir -p /workspace && \
mkdir -p ${VENV_PATH} && \
chmod -R 777 /workspaces ${VENV_PATH} && \
chgrp -R 0 /workspaces ${VENV_PATH}
RUN mkdir -p /workspaces && \
mkdir -p ${VENV_PATH} && \
chmod -R 777 /workspaces ${VENV_PATH} && \
chgrp -R 0 /workspaces ${VENV_PATH}
🤖 Prompt for AI Agents
.devcontainer/Dockerfile around lines 16 to 19: the Dockerfile creates
/workspace (singular) but the VENV_PATH and subsequent permission commands
target /workspaces (plural), causing a path mismatch; change the mkdir call to
create /workspaces (or better, use the same variable used for VENV_PATH) so the
directory created matches the paths used in chmod/chgrp, ensuring the venv
directory exists before setting permissions.


# SSH
EXPOSE 2222
28 changes: 28 additions & 0 deletions .devcontainer/create-aws-profile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env sh
set -ex

mkdir -p ~/.aws

if [ "$GITHUB_ACTIONS" = "true" ]; then
LOCALSTACK_ENDPOINT_URL="http://localhost:4566"
else
LOCALSTACK_ENDPOINT_URL="http://localstack:4566"
fi

cat >> ~/.aws/config <<EOF




Comment on lines +14 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Optional: Remove unnecessary blank lines in heredoc.

Lines 14-16 contain several blank lines before the profile configuration. While not breaking functionality, they add unnecessary whitespace to the AWS config file.

🔎 Proposed cleanup
 cat >> ~/.aws/config <<EOF
-
-
-
-
 [profile localstack]
 region=us-east-1
 output=json
 endpoint_url = $LOCALSTACK_ENDPOINT_URL
-
-
 EOF
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cat >> ~/.aws/config <<EOF
[profile localstack]
region=us-east-1
output=json
endpoint_url = $LOCALSTACK_ENDPOINT_URL
EOF
🤖 Prompt for AI Agents
In .devcontainer/create-aws-profile.sh around lines 14 to 16 there are
unnecessary blank lines inside the heredoc that insert extra whitespace into the
generated AWS config; remove the blank lines so the heredoc starts immediately
with the profile configuration (ensure no leading empty lines exist between the
heredoc opener and the first config line) and keep the rest of the heredoc
content unchanged.

[profile localstack]
region=us-east-1
output=json
endpoint_url = $LOCALSTACK_ENDPOINT_URL


EOF
cat >> ~/.aws/credentials <<EOF
[localstack]
aws_access_key_id=test
aws_secret_access_key=test
EOF
Comment on lines +12 to +28
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider making the script idempotent.

The script uses >> (append) to add AWS configuration and credentials. If the script runs multiple times (e.g., container rebuild, manual re-run), it will create duplicate profile entries in ~/.aws/config and ~/.aws/credentials.

🔎 Proposed fix for idempotency
 mkdir -p ~/.aws

 if [ "$GITHUB_ACTIONS" = "true" ]; then
   LOCALSTACK_ENDPOINT_URL="http://localhost:4566"
 else
   LOCALSTACK_ENDPOINT_URL="http://localstack:4566"
 fi

+# Remove existing localstack profile if present
+if [ -f ~/.aws/config ]; then
+  sed -i '/\[profile localstack\]/,/^$/d' ~/.aws/config
+fi
+if [ -f ~/.aws/credentials ]; then
+  sed -i '/\[localstack\]/,/^$/d' ~/.aws/credentials
+fi
+
 cat >> ~/.aws/config <<EOF


[profile localstack]
region=us-east-1
output=json
endpoint_url = $LOCALSTACK_ENDPOINT_URL


EOF
 cat >> ~/.aws/credentials <<EOF
[localstack]
aws_access_key_id=test
aws_secret_access_key=test
EOF
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cat >> ~/.aws/config <<EOF
[profile localstack]
region=us-east-1
output=json
endpoint_url = $LOCALSTACK_ENDPOINT_URL
EOF
cat >> ~/.aws/credentials <<EOF
[localstack]
aws_access_key_id=test
aws_secret_access_key=test
EOF
# Remove existing localstack profile if present
if [ -f ~/.aws/config ]; then
sed -i '/\[profile localstack\]/,/^$/d' ~/.aws/config
fi
if [ -f ~/.aws/credentials ]; then
sed -i '/\[localstack\]/,/^$/d' ~/.aws/credentials
fi
cat >> ~/.aws/config <<EOF
[profile localstack]
region=us-east-1
output=json
endpoint_url = $LOCALSTACK_ENDPOINT_URL
EOF
cat >> ~/.aws/credentials <<EOF
[localstack]
aws_access_key_id=test
aws_secret_access_key=test
EOF

62 changes: 62 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"dockerComposeFile": "docker-compose.yml",
"service": "devcontainer",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"features": {
"ghcr.io/devcontainers/features/python:1.7.1": {
// https://github.com/devcontainers/features/blob/main/src/python/devcontainer-feature.json
"version": "3.13.2",
"installTools": false,
"optimize": true
}
},
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
// basic tooling
// "eamodio.gitlens@15.5.1",
"coderabbit.coderabbit-vscode@0.16.1",
"ms-vscode.live-server@0.5.2025051301",
"MS-vsliveshare.vsliveshare@1.0.5905",
"github.copilot@1.388.0",
"github.copilot-chat@0.34.2025112401",

// Python
"ms-python.python@2025.17.2025100201",
"ms-python.vscode-pylance@2025.8.3",
"ms-vscode-remote.remote-containers@0.414.0",
"charliermarsh.ruff@2025.28.0",

// Misc file formats
"bierner.markdown-mermaid@1.28.0",
"samuelcolvin.jinjahtml@0.20.0",
"tamasfe.even-better-toml@0.19.2",
"emilast.LogFileHighlighter@3.3.3",
"esbenp.prettier-vscode@11.0.0"
],
"settings": {
"editor.accessibilitySupport": "off", // turn off sounds
"extensions.autoUpdate": false,
"extensions.autoCheckUpdates": false,
"livePreview.portNumber": 3025, // arbitrary not to conflict with default 3000 Nuxt port number
"github.copilot.nextEditSuggestions.allowWhitespaceOnlyChanges": false,
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff"
},
"ruff.nativeServer": "on",
// TODO: see if there's a way to specify different configurations for different folders
"ruff.configuration": "/workspaces/copier-vue-package-template/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded workspace path will break in instantiated templates.

The ruff.configuration path is hardcoded to this specific repository name. When users instantiate this template into their own repositories, this path will be invalid and Ruff configuration won't be applied.

Consider using a dynamic path or the ${workspaceFolder} variable:

🔎 Proposed fix
-        "ruff.configuration": "/workspaces/copier-vue-package-template/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
+        "ruff.configuration": "${workspaceFolder}/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"ruff.configuration": "/workspaces/copier-vue-package-template/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
"ruff.configuration": "${workspaceFolder}/ruff-test.toml", // use the test configuration since it's less restrictive and won't show false positives and underline things
🤖 Prompt for AI Agents
In .devcontainer/devcontainer.json around line 50 the ruff.configuration value
is hardcoded to "/workspaces/copier-vue-package-template/ruff-test.toml" which
will break in instantiated templates; change it to use the workspace variable
(e.g. "${workspaceFolder}/ruff-test.toml") or a relative path so the config
resolves dynamically in any repo, updating the JSON value accordingly.

"[jsonc][json][javascript][typescript][graphql][css][scss][html][vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
}
}
},
"initializeCommand": "sh .devcontainer/initialize-command.sh",
"onCreateCommand": "sh .devcontainer/on-create-command.sh",
"postStartCommand": "sh .devcontainer/post-start-command.sh"
// Devcontainer context hash (do not manually edit this, it's managed by a pre-commit hook): 1ac9e66a # spellchecker:disable-line
}
23 changes: 23 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
services:
devcontainer:
# added the platform flag to override any local settings since this image is only compatible with linux/amd64.
platform: linux/amd64
build:
context: .
args:
REPO_NAME: copier-vue-package-template
# You can run `devcontainer-info content-url` in codespaces to see what image base is
volumes:
- ..:/workspaces/copier-vue-package-template:cached
# Break out the venv folder as a separate docker volume for better performance on Windows hosts
- python_venv:/workspaces/copier-vue-package-template/.venv
command: sleep infinity
ports:
- "51211:2222"
environment:
- AWS_PROFILE=localstack
- AWS_DEFAULT_REGION=us-east-1


volumes:
python_venv: {}
7 changes: 7 additions & 0 deletions .devcontainer/envs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"description": "main",
"relative_directory": ".",
"package_manager": "uv"
}
]
8 changes: 8 additions & 0 deletions .devcontainer/initialize-command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# CodeSpaces build environments get cluttered and need to be pruned https://github.com/orgs/community/discussions/50403
# There was an error encountered during the codespace build using `docker system prune`, so switched to `docker image prune`: Error: The expected container does not exist.
set -ex

printenv
if [ -n "$CODESPACES" ] && [ "$CODESPACES" = "true" ]; then
docker image prune --all --force
fi
Comment on lines +1 to +8
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add shebang to declare the shell interpreter.

The script uses set -ex and bash-specific features but lacks a shebang line. This can cause the script to be executed with the wrong shell interpreter, leading to unexpected behavior or failures.

🔎 Proposed fix
+#!/bin/bash
 # CodeSpaces build environments get cluttered and need to be pruned https://github.com/orgs/community/discussions/50403
 # There was an error encountered during the codespace build using `docker system prune`, so switched to `docker image prune`: Error: The expected container does not exist.
 set -ex
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# CodeSpaces build environments get cluttered and need to be pruned https://github.com/orgs/community/discussions/50403
# There was an error encountered during the codespace build using `docker system prune`, so switched to `docker image prune`: Error: The expected container does not exist.
set -ex
printenv
if [ -n "$CODESPACES" ] && [ "$CODESPACES" = "true" ]; then
docker image prune --all --force
fi
#!/bin/bash
# CodeSpaces build environments get cluttered and need to be pruned https://github.com/orgs/community/discussions/50403
# There was an error encountered during the codespace build using `docker system prune`, so switched to `docker image prune`: Error: The expected container does not exist.
set -ex
printenv
if [ -n "$CODESPACES" ] && [ "$CODESPACES" = "true" ]; then
docker image prune --all --force
fi
🧰 Tools
🪛 Shellcheck (0.11.0)

[error] 1-1: Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

(SC2148)

🤖 Prompt for AI Agents
.devcontainer/initialize-command.sh lines 1-8: the script uses bash-specific
features (set -ex) but has no shebang, so ensure the shell interpreter is
declared by adding a shebang as the very first line (e.g. #!/usr/bin/env bash)
to force bash execution; save the file with the shebang at the top and verify
executable permissions if needed.

164 changes: 164 additions & 0 deletions .devcontainer/install-ci-tooling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import argparse
import os
import platform
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

UV_VERSION = "0.9.18"
PNPM_VERSION = "10.25.0"
COPIER_VERSION = "==9.11.0"
COPIER_TEMPLATE_EXTENSIONS_VERSION = "==0.3.3"
PRE_COMMIT_VERSION = "4.5.0"
GITHUB_WINDOWS_RUNNER_BIN_PATH = r"C:\Users\runneradmin\.local\bin"
INSTALL_SSM_PLUGIN_BY_DEFAULT = False
parser = argparse.ArgumentParser(description="Install CI tooling for the repo")
_ = parser.add_argument(
"--no-python",
default=False,
action="store_true",
help="Do not process any environments using python package managers",
)
_ = parser.add_argument(
"--python-version",
default=f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
type=str,
help="What version to install.",
)
_ = parser.add_argument(
"--no-node", action="store_true", default=False, help="Do not process any environments using node package managers"
)
_ = parser.add_argument(
"--skip-installing-ssm-plugin",
action="store_true",
default=False,
help="Skip installing the SSM plugin for AWS CLI",
)


def main():
args = parser.parse_args(sys.argv[1:])
is_windows = platform.system() == "Windows"
uv_env = dict(os.environ)
uv_env.update({"UV_PYTHON": args.python_version, "UV_PYTHON_PREFERENCE": "only-system"})
uv_path = ((GITHUB_WINDOWS_RUNNER_BIN_PATH + "\\") if is_windows else "") + "uv"
if is_windows:
pwsh = shutil.which("pwsh") or shutil.which("powershell")
if not pwsh:
raise FileNotFoundError("Neither 'pwsh' nor 'powershell' found on PATH")
if not args.no_python:
if is_windows:
uv_env.update({"PATH": rf"{GITHUB_WINDOWS_RUNNER_BIN_PATH};{uv_env['PATH']}"})
# invoke installer in a pwsh process
_ = subprocess.run(
[
pwsh, # type: ignore[reportPossiblyUnboundVariable] # this matches the conditional above that defines pwsh
"-NoProfile",
"-NonInteractive",
"-Command",
f"irm https://astral.sh/uv/{UV_VERSION}/install.ps1 | iex",
],
check=True,
env=uv_env,
)
else:
_ = subprocess.run(
f"curl -fsSL --connect-timeout 20 --max-time 40 --retry 3 --retry-delay 5 --retry-connrefused --proto '=https' https://astral.sh/uv/{UV_VERSION}/install.sh | sh",
check=True,
shell=True,
env=uv_env,
)
Comment on lines +66 to +72
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider security implications of piping curl to shell.

While common, curl | sh patterns can be risky. The --proto '=https' flag is good, but consider downloading and verifying the script first, or using a checksummed approach.

🤖 Prompt for AI Agents
In .devcontainer/install-ci-tooling.py around lines 66 to 72, the current
implementation pipes curl output directly to sh which is a security risk; change
to download the installer to a temporary file first, fetch an expected checksum
or signature (or the installer’s release metadata), verify the downloaded file
matches the checksum or validate its signature, make the file executable and run
it from disk, and fail if verification does not pass; alternatively prefer
installing via a package manager or a verified release artifact if available.

# TODO: add uv autocompletion to the shell https://docs.astral.sh/uv/getting-started/installation/#shell-autocompletion
_ = subprocess.run(
[
uv_path,
"tool",
"install",
f"copier{COPIER_VERSION}",
"--with",
f"copier-template-extensions{COPIER_TEMPLATE_EXTENSIONS_VERSION}",
],
check=True,
env=uv_env,
)
_ = subprocess.run(
[
uv_path,
"tool",
"install",
f"pre-commit=={PRE_COMMIT_VERSION}",
],
check=True,
env=uv_env,
)
_ = subprocess.run(
[
uv_path,
"tool",
"list",
],
check=True,
env=uv_env,
)
if not args.no_node:
pnpm_install_sequence = ["npm -v", f"npm install -g pnpm@{PNPM_VERSION}", "pnpm -v"]
for cmd in pnpm_install_sequence:
cmd = (
[
pwsh, # type: ignore[reportPossiblyUnboundVariable] # this matches the conditional above that defines pwsh
"-NoProfile",
"-NonInteractive",
"-Command",
cmd,
]
if is_windows
else [cmd]
)
_ = subprocess.run(cmd, shell=True, check=True)
Comment on lines +105 to +119
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify shell=True with list argument behavior.

When is_windows is False, cmd becomes [cmd_string] (a single-element list) and shell=True is passed. With shell=True and a list, the first element is the command and rest are arguments to the shell, which may not work as intended.

On non-Windows, the code should either use shell=True with a string, or shell=False with a properly split list.

🔎 Proposed fix
     if not args.no_node:
         pnpm_install_sequence = ["npm -v", f"npm install -g pnpm@{PNPM_VERSION}", "pnpm -v"]
         for cmd in pnpm_install_sequence:
-            cmd = (
+            run_cmd: list[str] | str = (
                 [
                     pwsh,  # type: ignore[reportPossiblyUnboundVariable] # this matches the conditional above that defines pwsh
                     "-NoProfile",
                     "-NonInteractive",
                     "-Command",
                     cmd,
                 ]
                 if is_windows
-                else [cmd]
+                else cmd  # Keep as string for shell=True on non-Windows
             )
-            _ = subprocess.run(cmd, shell=True, check=True)
+            _ = subprocess.run(run_cmd, shell=not is_windows, check=True)
🤖 Prompt for AI Agents
In .devcontainer/install-ci-tooling.py around lines 105 to 119, the
subprocess.run call passes shell=True along with a single-element list on
non-Windows which is incorrect; change the logic so that when is_windows is
False you pass a plain string to subprocess.run with shell=True (or
alternatively set shell=False and pass a properly split list using
shlex.split(cmd_string)); ensure the Windows branch continues to pass a list and
shell=True only if intended, and use check=True as before so exceptions still
propagate.

if INSTALL_SSM_PLUGIN_BY_DEFAULT and not args.skip_installing_ssm_plugin:
with tempfile.TemporaryDirectory() as tmp_dir:
if is_windows:
local_package_path = Path(tmp_dir) / "SessionManagerPluginSetup.exe"
# Based on https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-windows.html
# no specific reason for that version, just pinning it for best practice
_ = subprocess.run(
[
"curl",
"https://s3.amazonaws.com/session-manager-downloads/plugin/1.2.707.0/windows/SessionManagerPluginSetup.exe",
"-o",
f"{local_package_path}",
],
check=True,
)
_ = subprocess.run(
[str(local_package_path), "/quiet"],
check=True,
)
else:
local_package_path = Path(tmp_dir) / "session-manager-plugin.deb"
# Based on https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-debian-and-ubuntu.html
# no specific reason for that version, just pinning it for best practice
_ = subprocess.run(
[
"curl",
"https://s3.amazonaws.com/session-manager-downloads/plugin/1.2.707.0/ubuntu_64bit/session-manager-plugin.deb",
"-o",
f"{local_package_path}",
],
check=True,
)
_ = subprocess.run(
["sudo", "dpkg", "-i", str(local_package_path)],
check=True,
)
print("SSM Plugin Manager Version: ")
_ = subprocess.run(
["session-manager-plugin", "--version"],
check=True,
)


if __name__ == "__main__":
main()
Loading
Loading