-
Notifications
You must be signed in to change notification settings - Fork 11.9k
feat(@angular/cli): allow using Deno as package manager #30948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
alan-agius4
commented
Nov 18, 2025
@csvn, can you please rebase? Thanks.
This commits configures CI to run Deno E2E tests.
93e7cb3 to
38470cb
Compare
csvn
commented
Nov 20, 2025
Sorry for the delay, rebased now @alan-agius4 🙂
alan-agius4
commented
Nov 20, 2025
Looks like Deno has a bug. And the install is failing with Failed to parse "/package.json" as JSON. UnexpectedEndOfString at offset: 456.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to have changed.
deno --version
deno 2.5.6 (stable, release, x86_64-unknown-linux-gnu)
v8 14.0.365.5-rusty
typescript 5.9.2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... maybe this differs by platform? For me on Windows I get a shorter version output with -v, and a more verbose one with --version. That's why I added the ternary to switch to the -v flag on L224:
> PS C:\Users\csvn\dev\angular-cli> deno --version
deno 2.5.6 (stable, release, x86_64-pc-windows-msvc)
v8 14.0.365.5-rusty
typescript 5.9.2
> PS C:\Users\csvn\dev\angular-cli> deno -v
deno 2.5.6
I used the shorter one (-v) to simplify parsing the version correctly. But I could perhaps change to a regex to extract the version when using --version? Something along the lines of /deno (?<version>\S{5,})/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked into the E2E test errors yet, so I don't know why those fail. But I know it works to create a new Angular project with Deno like this:
> PS C:\Users\ChristianSvensson\Dev\_personal> deno run -Ar npm:@angular/cli new test-project --skip-install --test-runner karma
✔ Which stylesheet system would you like to use? CSS [ https://developer.mozilla.org/docs/Web/CSS]
✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No
✔ Which AI tools do you want to configure with Angular best practices? https://angular.dev/ai/develop-with-ai None
CREATE test-project/angular.json (2166 bytes)
...[snip]...
CREATE test-project/public/favicon.ico (15086 bytes)
Successfully initialized git.
> PS C:\Users\ChristianSvensson\Dev\_personal>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try to update to 2.5.6 to see if the Deno install issue has been addressed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in 4d0947a.
ac20240 to
f26427e
Compare
csvn
commented
Nov 20, 2025
I missed scope in my commits, force pushed to correct commit messages and address failing lint job. 😅
Lucostus
commented
Dec 4, 2025
Hi, any update? We would like to switch to Deno, due to the current Shai-Hulud attacks.
alan-agius4
commented
Dec 4, 2025
Hi, any update? We would like to switch to Deno, due to the current Shai-Hulud attacks.
But why?
Hi, any update? We would like to switch to Deno, due to the current Shai-Hulud attacks.
But why?
I think there's two reasons for this.
- Deno does not allow scripts access to env variables without explicit flags (either specific allowed environment variables or all of them)
- Directly in terminal or in
"tasks"indeno.json:deno run --allow-env=HOME,FOO script.ts
- Directly in terminal or in
- The
deno installcommand does not run NPM package lifecycle hooks without explicit opt-in via--allow-scriptsdeno install --allow-scripts
The two mitigations above helps prevent packages running code on install, and reading from env. I think these were the ways the Shai-Hulud NPM worm used to steal secrets?
I tried reading about --permission for NodeJS, but I can't see anything to block env-variable access yet. The NPM lifecycle hooks are related to package managers though, but I think NPM still runs them by default.
Possibly the reason anyway I think. 🙂
Using Deno or other package managers will not inherently prevent the package infected byShai-Hulud accessing your environment variables. Adopting security features like the minReleaseAge (found in package managers like pnpm and Yarn) is highly recommended as a prevention mechanism against malicious packages, as this is not a runtime defense. Moreover, although Deno and some package managers like pnpm disable pre-install scripts by default, which is a good security practice, the core vulnerability remains. If an infected package is successfully installed and executed, it can still exfiltrate your environment variables even from within a Deno environment. This is because the malicious payload is designed to run in a separate Bun environment as a child process. Since Deno's environment variable restriction is scoped only to the Deno runtime and does not prevent a spawned child process using a different runtime from accessing un-restricted system resources, the exploit effectively bypasses Deno's security model. Thus, while Deno is a secure runtime with a permissions model, it is not a true, comprehensive sandbox capable of insulating against such a multi-runtime attack and it's relatively easy for an attacker to get around.
csvn
commented
Dec 4, 2025
Using Deno or other package managers will not inherently prevent the package infected byShai-Hulud accessing your environment variables.
True, it won't stop any environment variables used by an application. But it can prevent prevent reading of a NPM token with publish access when running an application (NPM_TOKEN is not allowed to be read when running deno task serve)
Adopting security features like the
minReleaseAge(found in package managers like pnpm and Yarn) is highly recommended as a prevention mechanism against malicious packages, as this is not a runtime defense.
No defense is 100%, it's helpful to have multiple layers. Using minReleaseAge is definitely a good idea I agree.
If an infected package is successfully installed and executed, it can still exfiltrate your environment variables even from within a Deno environment. This is because the malicious payload is designed to run in a separate Bun environment as a child process. [...] Thus, while Deno is a secure runtime with a permissions model, it is not a true, comprehensive sandbox capable of insulating against such a multi-runtime attack and it's relatively easy for an attacker to get around.
I only think this is true when running Angular CLI via bun or node? If running @angular/cli via deno run (deno run npm:@angular/cli new ...) then it should not be possible to spawn child processes using Bun? I.e. it requires --allow-run/--allow-run="bun". Where does this attack escape Deno's sandbox without opting into it (-A for all or --allow-run) to run multi-runtime?
I don't mean to go into a debate in this PR. But I typically try to run with permissions I need (and not -A for all), so I could not see how Deno was vulnerable (crawling for secrets, running Bun as child process) via deno install or deno run --allow-env=AWS_SECRET_KEY main.ts (the AWS_SECRET_KEY in the example would of course be vulnerable if a dependency was infected but no secret to spread the worm via NPM_TOKEN would be).
alan-agius4
commented
Dec 4, 2025
You are correct, but to clarify, this pull request specifically focuses on adding support for the Deno package manager, not the Deno runtime. However, the runtime should still function because it is designed to be compatible with the Node.js runtime.
I pushed a commit to the PR to fix the issue with the json parsing issues during installation, however now the installation is failing due to missing permissions that are needed to create the bin.
hybrist
commented
Dec 4, 2025
I only think this is true when running Angular CLI via bun or node? If running @angular/cli via deno run (deno run npm:@angular/cli new ...) then it should not be possible to spawn child processes using Bun? I.e. it requires --allow-run/--allow-run="bun". Where does this attack escape Deno's sandbox without opting into it (-A for all or --allow-run) to run multi-runtime?
Well... when running the CLI, it might have to spawn subprocesses though. To run package manager installs, to run build tools like esbuild, etc.. And the second any subprocesses can be spawned, all the protections from deno's permission system are kind of out the window. It's very situational that deno's system helps and this isn't really one of those situations.
As @alan-agius4 mentioned, you definitely should consider using a package manager that doesn't run install scripts by default and has a per-package opt-in (e.g. pnpm or deno) and that offers some amount of cool-off. But for something like a web app, process-level permissions don't really help much with a supply chain attack. The web app process tree, especially in development mode / as a dev server, has likely all the permissions needed to do all the damage a supply chain attacker would want to do. If you are concerned there, running the app inside of a container or another OS-level sandbox would be something that really makes a difference.
P.S.: Also, more generally, please don't put credentials with write access into your shell. If at all possible, keep those out of your dev machines entirely. If you really need them on your dev machine, only source them where they are needed and consider using something that doesn't store them in plaintext on disk (e.g. the security CLI tool on macOS). But that's more defense in depth. :)
csvn
commented
Dec 4, 2025
I pushed a commit to the PR to fix the issue with the json parsing issues during installation, however now the installation is failing due to missing permissions that are needed to create the
bin.
I took a look, and it seems there's currently no flag to pass to deno init to allow this command for CI. It only spawns a prompt in the terminal if possible, asking "Deno will invoke code from it with all permissions".
Created denoland/deno#31498 to see if that's something they want to support. It would be possible to replace deno init with an equivalent deno run ... command, but that won't be helpful for testing purposes to verify deno init works. Sometimes they are very quick with adding needed flags 🙂
csvn
commented
Dec 4, 2025
Well... when running the CLI, it might have to spawn subprocesses though. To run package manager installs, to run build tools like esbuild, etc.. And the second any subprocesses can be spawned, all the protections from deno's permission system are kind of out the window. It's very situational that deno's system helps and this isn't really one of those situations.
Yes, only workers preserve the current permissions, child processes are subject to privilege escalation. Though I sometimes run code after adding new dependencies without any permissions just to check what they're trying to access.
But for something like a web app, process-level permissions don't really help much with a supply chain attack. The web app process tree, especially in development mode / as a dev server, has likely all the permissions needed to do all the damage a supply chain attacker would want to do.
You're right, it's not possible to limit permissions to "your own code" or specific packages. Using as few secrets as possible in application code with as few permissions as possible is always a good idea. Though it's rare these days to not require keys for third-party vendors/API's, e.g. Auth (Clerk, Auth0, Okta) when building an app.
P.S.: Also, more generally, please don't put credentials with write access into your shell. If at all possible, keep those out of your dev machines entirely.
Good advice 👍, and yeah we for instance only have read permissions on developer machines for private npm registry, never write.
If you really need them on your dev machine, only source them where they are needed and consider using something that doesn't store them in plaintext on disk (e.g. the security CLI tool on macOS). But that's more defense in depth. :)
Well, even in containers if a dependency is infected it may secrets/credentials and send them to an outside party from inside the container 😅
When we can we will likely switch to use the recent feature deno run --tunnel so env variables can be kept out of local machines and into Deno Deploy.
As you say with defense in depth, no single strategy covers everything. 🙂
csvn
commented
Dec 4, 2025
Pushed a fix for the lint error.
I pushed a commit to the PR to fix the issue with the json parsing issues during installation, however now the installation is failing due to missing permissions that are needed to create the
bin.
I tried running pnpm bazel test --config=e2e //tests/legacy-cli:e2e.deno_node22 to debug the failing E2E tests closer, but I see I must run this inside WSL on Windows. I'll see if I have time this weekend to look at it.
Uh oh!
There was an error while loading. Please reload this page.
PR Checklist
Please check to confirm your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: #30947
What is the new behavior?
It's possible to use
denoto install packages, similar tobun.Does this PR introduce a breaking change?
Other information