Skip to content

Conversation

@corneliusludmann
Copy link
Contributor

@corneliusludmann corneliusludmann commented Dec 3, 2025

What

  • Replace npx calls with globally available tools installed from dev/npm-tools
  • Pin tool versions via package-lock.json for reproducible builds
  • Add security hardening to both dev container images

Why

  • npx downloads and executes packages without version pinning, leading to inconsistent builds
  • Global npm install -g doesn't use a lockfile, so versions can drift
  • Security hardening reduces attack surface from malicious packages

Changes

New: dev/npm-tools/

  • package.json with pinned dependencies: typescript, prettier, yarn, pnpm, node-gyp, @anthropic-ai/claude-code
  • package-lock.json for reproducible installs

Dockerfiles (.devcontainer/Dockerfile, dev/image/Dockerfile)

  • Remove npm install -g for tools now in npm-tools
  • Install npm-tools via npm ci and symlink binaries to /usr/local/bin
  • Disable npm/yarn lifecycle scripts by default (security)
  • Disable npx (security)

Component package.json files

  • npx tsctsc
  • npx prettierprettier

Notes

  • Lifecycle scripts are disabled by default. Use npm rebuild <package> for packages requiring postinstall scripts.
  • npx is disabled. Use explicit package installation via npm-tools instead.

Fixes PDE-163
Fixes PDE-176

Copy link
Contributor

@kylos101 kylos101 left a comment

Choose a reason for hiding this comment

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

On L338 we do npm install, should we have a lockfile change added in this PR too, so that when npm install is done, it is constrained? For example, to use specific versions of typescript yarn pnpm node-gyp @anthropic-ai/claude-code.

Copy link
Contributor

@kylos101 kylos101 left a comment

Choose a reason for hiding this comment

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

Also, it would be great to duplicate these changes in dev/image/Dockerfile, and redo the image in .gitpod.yml, so that if/when workspaces are started in Classic for this repo, they have similar protection. Although for now, I'll exclusively use Ona to avoid such potential.

@socket-security
Copy link

socket-security bot commented Dec 3, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​xunit-viewer@​10.6.1981001007780
Addednpm/​bun@​1.3.3921007997100
Addednpm/​yarn@​1.22.22921008980100
Addednpm/​@​anthropic-ai/​claude-code@​2.0.571001008510070
Addednpm/​node-gyp@​10.3.1991001009380
Addednpm/​pnpm@​9.15.994931009780
Addednpm/​typescript@​5.9.31001009010090
Addednpm/​prettier@​3.7.4901009799100

View full report

@corneliusludmann corneliusludmann changed the title [dev] disable npm lifecycle scripts and npx Replace npx with pinned npm-tools and add security hardening Dec 3, 2025
Copy link
Contributor

@kylos101 kylos101 left a comment

Choose a reason for hiding this comment

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

👋 @corneliusludmann , I built and inspected the .devcontainer/Dockerfile.

  • npx also needs to be deleted from the nvm folder
  • I'm unsure what we're trying to accomplish by ignoring scripts at the user level (which I cannot inspect), instead of global
  • there are additional global package considerations (one for a test and the new dev/npm-tools, and one for Github workflows which I think should avoid dev/npm-tools)

Copy link
Contributor

Choose a reason for hiding this comment

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

@corneliusludmann should we put anything we install globally here?

If so, I think we'll want to add additional tools:

xunit-viewer

Copy link
Contributor

Choose a reason for hiding this comment

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

There are also many places in Github Workflows where we globally install bun.

But, I am thinking we don't want to use dev/npm-tools to install packages for each github workflow. And so, it should probably have it's own.

Copy link
Contributor

Choose a reason for hiding this comment

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

Built the image like:

vscode ➜ /workspaces/workspaces/gitpod (clu/npm-security-hardening) $ docker build -f .devcontainer/Dockerfile .

# Disable npx (security hardening - prevents arbitrary package execution)
RUN rm -f /usr/bin/npx /usr/local/bin/npx && \
echo '#!/bin/sh' > /usr/local/bin/npx && \
echo 'echo "npx is disabled for security reasons. Use explicit package installation instead." >&2' >> /usr/local/bin/npx && \
Copy link
Contributor

Choose a reason for hiding this comment

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

Works:

root / $ /usr/local/bin/npx
npx is disabled for security reasons. Use explicit package installation instead.

echo 'ignore-scripts true' >> ~/.yarnrc

# Disable npx (security hardening - prevents arbitrary package execution)
RUN rm -f /usr/bin/npx /usr/local/bin/npx && \
Copy link
Contributor

Choose a reason for hiding this comment

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

npx is also located as part of the nvm installation, we should remove it from here too:

Evidence:

vscode ➜ /workspaces/workspaces/gitpod (clu/npm-security-hardening) $ docker run -it abe5f93ace01
root / $ nvm which node
/root/.nvm/versions/node/v22.17.0/bin/node
root / $ which npx
/root/.nvm/versions/node/v22.17.0/bin/npx


# Disable npm/yarn lifecycle scripts by default (security hardening)
# To allow specific packages, use: npm rebuild <package> or yarn rebuild <package>
RUN npm config set ignore-scripts true --location=user && \
Copy link
Contributor

Choose a reason for hiding this comment

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

I see this is set for global:

npm config get ignore-scripts --location=global
true

But get an error at the user (default) level:

pm config get ignore-scripts --location=user
npm error code ENOWORKSPACES
npm error This command does not support workspaces.
npm error A complete log of this run can be found in: /root/.npm/_logs/2025-12-03T22_23_34_233Z-debug-0.log

What are we trying to accomplish here? Global makes sense to me, if we're talking a Dockerfile.

Copy link
Contributor

Choose a reason for hiding this comment

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

The latter part of the command seems okay:

cat $HOME/.yarnrc 
ignore-scripts true

But, I'm unsure of the former.

Copy link
Contributor

Choose a reason for hiding this comment

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

This file will need improvements similar to what I mentioned in .devcontainer/Dockerfile

@geropl
Copy link
Member

geropl commented Dec 4, 2025

Also, it would be great to duplicate these changes in dev/image/Dockerfile, and redo the image in .gitpod.yml, so that if/when workspaces are started in Classic for this repo, they have similar protection

Yes - that's also the image we use in the workflows. 👍

@corneliusludmann Next steps to have this built and merged are these here I think: https://gitpod.slack.com/archives/C071G5TTS49/p1764834081132659

Once the build is green (and the new dev-image is built as an side effect), we can raise a follow-up to use it everywhere, as Kyle suggested here. 👍
Alternatively you can try to build and push it from the environment, not sure how well that works 🤷

Cornelius Ludmann and others added 2 commits December 4, 2025 09:58
Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: Ona <no-reply@ona.com>
@geropl
Copy link
Member

geropl commented Dec 5, 2025

FYI I'm currently iterating on build issues here: #21169

corneliusludmann and others added 7 commits December 5, 2025 09:56
The symlink at /root/.nvm/.../bin/npx points to npx-cli.js.
Remove both to ensure npx is fully disabled.

Co-authored-by: Ona <no-reply@ona.com>
Replace self-hosted GCE runner pattern with GitHub-hosted ubuntu-latest runners across all workflows. This removes the three-phase pattern (create-runner, use-runner, delete-runner) and simplifies workflow execution.

Changes:
- Remove create-runner and delete-runner jobs from all workflows
- Replace runs-on: ${{ needs.create-runner.outputs.label }} with runs-on: ubuntu-latest
- Remove create-runner from job dependencies
- Preserve all other job dependencies and concurrency controls

Affected workflows:
- build.yml (8 jobs)
- workspace-integration-tests.yml (4 jobs)
- ide-integration-tests.yml (4 jobs)
- preview-env-check-regressions.yml (4 jobs)
- preview-env-gc.yml (2 jobs)
- jetbrains-auto-update-template.yml (1 job)
- jetbrains-integration-test.yml (1 job)
- code-nightly.yml (1 job)
- preview-env-delete.yml (1 job)

Co-authored-by: Ona <no-reply@ona.com>
Add 'options: --user root' to all container configurations to resolve EACCES permission errors when GitHub Actions tries to write to internal directories.

GitHub-hosted runners require containers to run as root to allow the Actions runtime to write to /__w/_temp/_runner_file_commands/ and other internal paths.

Affected workflows:
- build.yml (3 container jobs)
- workspace-integration-tests.yml (2 container jobs)
- ide-integration-tests.yml (2 container jobs)
- preview-env-check-regressions.yml (1 container job)
- preview-env-gc.yml (1 container job)
- jetbrains-auto-update-template.yml (1 container job)
- jetbrains-integration-test.yml (1 container job)
- code-nightly.yml (1 container job)

Co-authored-by: Ona <no-reply@ona.com>
Create leeway generic build for dev/npm-tools and use it as a dependency in dev/image:docker build. This resolves the build error where npm-tools files were not accessible during Docker build.

Changes:
- Add dev/npm-tools/BUILD.yaml with generic package containing package.json and package-lock.json
- Add dev/npm-tools:pkg as dependency in dev/image/BUILD.yaml
- Update Dockerfile to use COPY from leeway dependency path (dev-npm-tools--pkg/)

This follows the established pattern used in other builds like install/installer where dependencies are copied from leeway-generated paths.

Co-authored-by: Ona <no-reply@ona.com>
Add chown command to fix EACCES permission error when installing npm-tools. The COPY command creates files owned by root, but npm ci runs as gitpod user and needs write access to create node_modules.

Changes:
- Add 'sudo chown -R gitpod:gitpod /opt/npm-tools' before npm ci
- This ensures the gitpod user can write to /opt/npm-tools/node_modules/

Error fixed:
  npm error code EACCES
  npm error syscall mkdir
  npm error path /opt/npm-tools/node_modules
  npm error errno -13

Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: Ona <no-reply@ona.com>
curl -fsSL https://github.com/csweichel/oci-tool/releases/download/v0.2.1/oci-tool_0.2.1_linux_amd64.tar.gz | tar xz -C /usr/local/bin
chmod +x /usr/local/bin/oci-tool
cd ./components/ide/gha-update-image/
cd ./dev/npm-tools && npm ci
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, non-blocking:
The only con here, is we're installing more tools at runtime than we need, so, it means the workflows will take that much longer.

But, I think we can live with this, for the short time Classic remains.

@Ona-Security-Admin Ona-Security-Admin merged commit e9f25f4 into main Dec 5, 2025
7 of 8 checks passed
@Ona-Security-Admin Ona-Security-Admin deleted the clu/npm-security-hardening branch December 5, 2025 15:25
@geropl geropl deployed to branch-build December 5, 2025 17:04 — with GitHub Actions Active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants