Skip to content

JS-1373 Feature/devcontainer#6444

Draft
francois-mora-sonarsource wants to merge 31 commits intomasterfrom
feature/devcontainer
Draft

JS-1373 Feature/devcontainer#6444
francois-mora-sonarsource wants to merge 31 commits intomasterfrom
feature/devcontainer

Conversation

@francois-mora-sonarsource
Copy link
Contributor

Part of

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod bot changed the title Feature/devcontainer JS-1373 Feature/devcontainer Feb 24, 2026
@hashicorp-vault-sonar-prod
Copy link

hashicorp-vault-sonar-prod bot commented Feb 24, 2026

JS-1373

@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2026

Ruling Report

Code no longer flagged (3 issues)

S7728

TypeScript/src/services/formatting/rulesMap.ts:32

    30 | 
    31 |         public FillRules(rules: Rule[], rulesBucketConstructionStateList: RulesBucketConstructionState[]): void {
>   32 |             rules.forEach((rule) => {
    33 |                 this.FillRule(rule, rulesBucketConstructionStateList);
    34 |             });

TypeScript/src/services/formatting/rulesMap.ts:46

    44 |             const specificRule = rule.Descriptor.LeftTokenRange.isSpecific() && rule.Descriptor.RightTokenRange.isSpecific();
    45 | 
>   46 |             rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => {
    47 |                 rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => {
    48 |                     const rulesBucketIndex = this.GetRuleBucketIndex(left, right);

TypeScript/src/services/formatting/rulesMap.ts:47

    45 | 
    46 |             rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => {
>   47 |                 rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => {
    48 |                     const rulesBucketIndex = this.GetRuleBucketIndex(left, right);
    49 | 

Introduce .claude/skills/ with five skills that cover the most common
developer workflows: build pipeline, rule testing, ruling tests, new
rule creation, and rule options architecture. Content sourced from
docs/BUILD.md and docs/DEV.md.

Simplify CLAUDE.md and .claude/rules.md by moving detailed procedural
sections into their respective skills, reducing context window usage.
Update .gitignore to track .claude/skills/ and ignore settings files.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Use valid tag 24-bookworm instead of non-existent 1-24-bookworm.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The javascript-node devcontainer image uses `node` as its non-root user,
not `vscode` (which is specific to devcontainers/base images). Update
all references in the Dockerfile and devcontainer.json accordingly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
mise requires explicit trust for config files outside the home directory.
Run `mise trust` before `mise install` to avoid the untrusted config error.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Place *.pem or *.crt files in .devcontainer/certs/ (gitignored) and
they will be trusted by Node.js and system tools at image build time.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Replaces the COPY-from-gitignored-dir approach with the same
--mount=type=secret pattern used in the vibe-bot. The secret is
optional (required=false), so the image builds cleanly without a cert.

Developers on corporate networks can enable it by adding to devcontainer.json:
  "build": { "options": ["--secret", "id=sonar_cert,src=/path/to/cert.pem"] }

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Uses initializeCommand to copy the cert from $NODE_EXTRA_CA_CERTS (the
standard Node.js env var) if set on the host, or create an empty
placeholder otherwise. The file is then bind-mounted into the container
and merged into a CA bundle before npm ci runs.

Developers on corporate networks just need NODE_EXTRA_CA_CERTS set in
their shell profile — no devcontainer.json edits required.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Use an absolute host path (/tmp/devcontainer-corporate-ca.crt) instead
of a workspace-relative path. When cloning a repo into a container
volume, ${localWorkspaceFolder} resolves inside the volume rather than
on the host, causing the bind mount to fail.

initializeCommand always runs on the host, so writing to /tmp works
regardless of whether the workspace is a local folder or a Docker volume.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
VS Code does not apply wslpath conversion to user-specified mounts, so
/tmp/... is passed as-is to Docker Desktop which resolves it in the
docker-desktop WSL2 distro (not Ubuntu-24.04 where the file was created).

Use the UNC path format //wsl.localhost/$WSL_DISTRO_NAME/tmp/... which
Docker Desktop can locate unambiguously. WSL_DISTRO_NAME is set
automatically by WSL2 — no developer action required.

wslpath is also used in initializeCommand to handle NODE_EXTRA_CA_CERTS
being a Windows path (e.g. C:\...) by converting it to a WSL path first.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
${localEnv:...} for clone-in-container is evaluated in the Windows VS Code
process, not WSL2. TEMP is available there (C:\Users\...\AppData\Local\Temp)
but WSL2-specific vars like WSL_DISTRO_NAME are not.

initializeCommand now uses cmd.exe to get the Windows TEMP path and
wslpath to convert it to the WSL-accessible /mnt/c/... form, so the cert
lands on the Windows filesystem — readable from any WSL2 distro (including
docker-desktop) and from Docker Desktop's daemon via the same path.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
devcontainer substitutes ${localEnv:...} in all fields before running
the command, so ${localEnv:TEMP} is already the Windows path by the
time bash receives it. No need to call cmd.exe to retrieve it.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
devcontainer substitutes ${localEnv:...} before running the command,
so we can use it consistently alongside ${localEnv:TEMP} instead of
relying on the bash variable $NODE_EXTRA_CA_CERTS.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…orts clone-in-container

Replace the previous inline cert-only command with a simpler approach that:
- Uses ${localEnv:TEMP:/tmp} for a cross-platform staging path (Windows TEMP or /tmp fallback)
- Stages both the corporate CA cert and ~/.npmrc into the temp dir
- Works for both open-folder-in-container and clone-in-container workflows
- Requires no workspace files, so the script runs before the repo is cloned
- Bind-mounts the staged files into /tmp/corporate-ca.crt and /home/node/.npmrc

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Reverts the PowerShell approach (Windows-only) in favour of a portable bash
command that works across all environments:
- WSL2 bash: wslpath converts Windows TEMP to /mnt/c/...
- Git Bash (Windows): cygpath converts Windows TEMP to /c/...
- macOS/Linux: both unavailable, falls back to /tmp

Also stages ~/.npmrc alongside the CA cert so the Repox token is available
inside the container without manual setup.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…aths

MSYS2 (Git Bash) cannot resolve 8.3 shortname directories like FRANCO~1.MOR
via its POSIX filesystem layer, so touch/cp silently fail and the bind mount
source file is never created — Docker then creates a directory at the target
path instead of a file.

Fix: detect Windows paths (non-/ prefix in TEMP) and delegate to cmd.exe,
which uses Windows APIs that handle 8.3 shortnames natively via %TEMP%.
Linux/macOS paths (starting with /) use the existing bash branch unchanged.

Also make postCreateCommand skip the cert file when it is a directory
(defensive against future bind mount failures).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Root cause: MSYS2 (Git Bash) cannot resolve 8.3 shortname directories
(e.g. FRANCO~1.MOR) via its POSIX layer, so touch/cp would fail when
cygpath converted Windows TEMP to /c/Users/FRANCO~1.MOR/....

Key insight: in Git Bash, /tmp is MSYS2's mapping of Windows TEMP itself,
so writing to /tmp already creates the file at the Windows TEMP path that
Docker Desktop uses for the bind mount source.

New logic:
- WSL2 (/proc/version contains "microsoft"): wslpath converts Windows TEMP
  to /mnt/c/... so the file is written to the Windows filesystem
- Git Bash + Linux/macOS: write directly to /tmp (Git Bash maps this to
  Windows TEMP; Linux/macOS /tmp is Docker-accessible directly)

Also make postCreateCommand skip the cert file if it is a directory
(defensive against any future bind mount failure).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Previously only 5 of 9 skills were listed. Add the missing:
/rule-implementation, /helpers, /tests, /test-quality-standards

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…sistency

Aligns the bind mount target name with the staging file name so both sides
of the mount use the same filename.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Host filesystem bind mounts were unreliable on Windows due to 8.3 shortname
paths in %TEMP% that WSL2 DrvFS cannot resolve, causing Docker to create
directories instead of files at the mount targets.

New approach:
- initializeCommand runs init-host.sh from WSL2 context (open folder via
  "code ." in WSL2 terminal)
- init-host.sh creates a Docker named volume (dc-sonarjs-secrets) and uses
  a temporary alpine container to copy the cert and ~/.npmrc into it; Docker
  can mount WSL2 paths directly so no path translation is needed
- devcontainer mounts the named volume at /run/secrets (no path issues)
- postCreateCommand copies dc-npmrc to ~/.npmrc and builds the cert bundle
  from dc-cert.crt before running npm ci

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Moves Claude Code skill files and CLAUDE.md updates out of this branch.
This branch now focuses solely on the devcontainer and mise configuration.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@sonarqube-next
Copy link

Quality Gate passed Quality Gate passed

Issues
0 New issues
0 Fixed issues
0 Accepted issues

Measures
0 Security Hotspots
0 Dependency risks
No data about Coverage
No data about Duplication

See analysis details on SonarQube

Replaces the bash init-host.sh with init-host.js, which reads ~/.npmrc
and pipes it via stdin into the Docker named volume — avoiding all bind
mount and WSL2 path issues. Certificate support is now expected via
.npmrc (cafile= / strict-ssl=false). If Node.js is unavailable the
initializeCommand falls back gracefully via shell || operator.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
🤖 Generated with GitHub Actions
Extends init-host.js to also pipe ~/.m2/settings.xml into the
dc-sonarjs-secrets volume (as dc-m2-settings.xml), following the same
stdin-pipe pattern used for .npmrc. The postCreateCommand copies it to
~/.m2/settings.xml inside the container so Maven can authenticate
against Repox. Empty placeholders are created when the file is absent.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The repo root package.json has "type": "module", which made Node.js
treat init-host.js as an ES module and reject require() calls.
Renaming to .cjs forces CommonJS resolution regardless of package type.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Maven encrypted passwords (e.g. {ENCRYPTED_VALUE}) require the master
key in settings-security.xml to be decrypted. Without it, Maven cannot
authenticate against Repox. Also removes the empty placeholder creation
for settings.xml: an empty XML file causes a SAXParseException in Maven,
whereas a missing file is safely ignored.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
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