Baroshem / nuxt-security

🛡 Automatically configure your app to follow OWASP security patterns and principles by using HTTP Headers and Middleware
https://nuxt-security.vercel.app/
MIT License
743 stars 56 forks source link

Error deploying to Cloudflare Workers after upgrade beyond rc.2 #335

Closed nicgene closed 5 months ago

nicgene commented 6 months ago

Version

Steps to reproduce

Upgrading nuxt-security beyond 1.0.0-rc.2 breaks deployment to Cloudflare Workers using preset cloudflare_module.

ERROR Cannot resolve "node-fetch-native/native/proxy" from "..." and externals are not allowed!

Baroshem commented 6 months ago

Hey Buddy,

Thanks for reporting this issue.

Could you share your nuxt.config.ts file?

Current issue details does not ring a bell for me :(

nicgene commented 6 months ago
export default defineNuxtConfig({
  modules: [
    "nuxt-security",
  ],
  security: {
    headers: {
      crossOriginEmbedderPolicy: process.env.NODE_ENV === "development" ? "unsafe-none" : "require-corp",
      contentSecurityPolicy: {
        "img-src": [
          "'self'",
          "data:",
          "https://imagedelivery.net"
        ],
        "script-src": [
          "'nonce-{{nonce}}'",
          "'strict-dynamic'",
          "'unsafe-eval'"
        ]
      }
    },
    rateLimiter: false
  }
});
nicgene commented 6 months ago

https://github.com/nuxt/image/issues/1168

Baroshem commented 6 months ago

Thanks for sharing the nuxt configuration, the file look fine.

It does not look to me like there is some kind of issue with NuxtSecurity.

Could you try disabling the module or removing it for a test to see if it will still result in a bug after deploying to Cloudflare?

nicgene commented 6 months ago

Deployment to Cloudflare works with nuxt-security disabled. I have this issue on two Nuxt sites deployed to Workers. I just tried updating the other site from rc.2 to 1.0.0 and received the error.

Baroshem commented 6 months ago

I see. Thanks for verification.

One more question if I may.

You have upgraded your app from 1.0.0-rc.2 to 1.0.0 directly or to 1.0.0-rc.3 and received an error?

I am trying to figure out if the issue is in certain RC version or somewhere in the commits for 1.0.0

nicgene commented 6 months ago

I upgraded to rc.3 and rc.4 before upgrading to 1.0.0. and could reproduce the issue using releases after rc.2. (Never tried rc.5)

If I can do anything else to help diagnose, happy to help. Thanks.

Baroshem commented 6 months ago

Don't have much clue to be honest apart from one trail.

I looked at the changes in the rc.3 and the only one that could cause this bug imo is the introduction of cheerio tool.

I have located that it is used in three plugin files:

  1. Nonce
  2. Subresource Integrity
  3. CSP SSG

Could you try to set all three of them to false (disable them) from the config globally and deploy the app to Cloudflare with NuxtSecurity 1.0.0 and see if the problem occurs?

If that is not the case, maybe there is some issue with Cloudlfare building the project (guessing by these ... instead of proper relative path)

nicgene commented 6 months ago

I updated my config to the following and tried deploying but still getting the error.

security: {
    headers: {
      crossOriginEmbedderPolicy: process.env.NODE_ENV === "development" ? "unsafe-none" : "require-corp",
      contentSecurityPolicy: false,
    },
    rateLimiter: false,
    nonce: false,
    sri: false,
    ssg: false
  }

The build pipeline on gitlab has a better error log I think from the newer version of Wrangler.

[info] [nitro] Building Nitro Server (preset: `cloudflare_module`)
(node-resolve plugin) Could not resolve import "node-fetch-native/native/proxy" in /builds/.../node_modules/giget/dist/index.mjs using exports defined in /builds/.../node_modules/node-fetch-native/package.json.
[error] [nitro] Error: Cannot resolve "node-fetch-native/native/proxy" from "/builds/.../node_modules/giget/dist/index.mjs" and externals are not allowed!
undefined
[error] Cannot resolve "node-fetch-native/native/proxy" from "/builds/.../node_modules/giget/dist/index.mjs" and externals are not allowed!
  at Object.resolveId (node_modules/nitropack/dist/shared/nitro.4ea992bc.mjs:1973:17)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/rollup/dist/es/shared/node-entry.js:18539:28)
  at async resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17208:26)
  at async ModuleLoader.resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17622:15)
  at async Object.resolveId (node_modules/@rollup/plugin-commonjs/dist/es/index.js:588:10)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/rollup/dist/es/shared/node-entry.js:18539:28)
  at async resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17208:26)
  at async ModuleLoader.resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17622:15)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/rollup/dist/es/shared/node-entry.js:18539:28)
  at async resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17208:26)
  at async ModuleLoader.resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17622:15)
  at async Object.resolveId (node_modules/@rollup/plugin-commonjs/dist/es/index.js:588:10)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/rollup/dist/es/shared/node-entry.js:18539:28)
  at async resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17208:26)
  at async ModuleLoader.resolveId (node_modules/rollup/dist/es/shared/node-entry.js:17622:15)
  at async node_modules/rollup/dist/es/shared/node-entry.js:17929:50 
[error] Cannot resolve "node-fetch-native/native/proxy" from "/builds/.../node_modules/giget/dist/index.mjs" and externals are not allowed!
error Command failed with exit code 1.
Baroshem commented 6 months ago

This error certainly gives more info.

Giget is an unjs package that I think is used in Nuxt/Nitro.

https://github.com/unjs/giget

Not sure however, why does it fail your pipeline. Maybe NuxtSecurity has a newer version of Nuxt than your project previously had and this giget was included in there? This is me mainly guessing because I have no real clue what could be an issue.

@pi0 do you maybe have some ideas?

nicgene commented 6 months ago

I ran npx nuxi upgrade --force and npx nuxi cleanup and also tried deleting node_modules. Couldn't get it to deploy.

Yesterday I messaged a reddit user having the same issue. (https://www.reddit.com/r/Nuxt/comments/18tycmz/cant_deploy_nuxt_390_app_on_vercel_edge/) Removing nuxt-security fixed deployment on Vercel edge for them. "The error logs never suggested anything related to it but as soon as I removed it it deployed successfully to Vercel-edge."

Baroshem commented 6 months ago

@nicgene

Could you please let this Reddit User know that there is an issue here that we are trying to figure out how to fix? Maybe he will be able to share some valuable insights into his project that could help us resolve it :)

Baroshem commented 6 months ago

Also, could you check what Nuxt/Nigro versions do you have in your yarn lock after installing the Nuxt Security?

Maybe adding it bumps the package that then fails?

I would love to help but to be honest I have no clues what could be causing these issues. Usually issues are at least in some way related to the module functionalities while this one seems completely random as I am not using giget directly in any way.

vejja commented 6 months ago

Looks like potentially a version dependency mismatch somewhere ? @nicgene did you try one of these by any chance

nicgene commented 6 months ago

@Baroshem Yarn lock shows Nuxt 3.9.0 and Nitro 2.8.1. This is very random.

@vejja Yes, everything except purging cache on Cloudflare. Unless I'm mistaken that feature is only for Cloudflare Pages.

unr commented 5 months ago

We are also noticing the same issue when building for CF Pages.

Baroshem commented 5 months ago

@unr

Hey, could you share what kind of error you get? I am trying to get the most details because I have no idea what can be causing this error. It does not seem to come from the module specifically but rather one of its dependencies.

unr commented 5 months ago

We were using 0.13.0 and realized there was a 1.0.0 release.

GH Actions to run nuxt build, then push up to CF Workers.

When we run the build on nuxt-security@1.0.0 the build dies right at the end before completing with the following error:

(node-resolve plugin) Could not resolve import "node-fetch-native/native/proxy" in /opt/_work/myproject/node_modules/.pnpm/giget@1.2.1/node_modules/giget/dist/index.mjs using exports defined in /opt/_work/myproject/node_modules/.pnpm/node-fetch-native@1.6.1/node_modules/node-fetch-native/package.json.
Error:  [nitro] Error: Cannot resolve "node-fetch-native/native/proxy" from "/opt/_work/myproject/node_modules/.pnpm/giget@1.2.1/node_modules/giget/dist/index.mjs" and externals are not allowed!

undefined
Error:  Cannot resolve "node-fetch-native/native/proxy" from "/opt/_work/myproject/node_modules/.pnpm/giget@1.2.1/node_modules/giget/dist/index.mjs" and externals are not allowed!
  at Object.resolveId (node_modules/.pnpm/nitropack@2.8.1/node_modules/nitropack/dist/shared/nitro.4ea992bc.mjs:1973:17)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:18542:28)
  at async resolveId (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:17211:26)
  at async ModuleLoader.resolveId (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:17625:15)
  at async Object.resolveId (node_modules/.pnpm/@rollup+plugin-commonjs@25.0.7_rollup@4.9.2/node_modules/@rollup/plugin-commonjs/dist/es/index.js:588:10)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:18542:28)
  at async resolveId (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:17211:26)
  at async ModuleLoader.resolveId (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:17625:15)
  at async PluginDriver.hookFirstAndGetPlugin (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:18542:28)
  at async resolveId (node_modules/.pnpm/rollup@4.9.2/node_modules/rollup/dist/es/shared/node-entry.js:17211:26) 

Error:  Cannot resolve "node-fetch-native/native/proxy" from "/opt/_work/myproject/node_modules/.pnpm/giget@1.2.1/node_modules/giget/dist/index.mjs" and externals are not allowed!
 ELIFECYCLE  Command failed with exit code 1.
Error: Process completed with exit code 1.

This happens both on Nuxt 3.8.2 and 3.9.0 for us.

vejja commented 5 months ago

@Baroshem I can see that the log from @unr is trying to use node-fetch-native from nitropack@v2.8.1 which I understand is v1.6.1 Our module pins node-fetch-native to v1.4.1 in yarn.lock Maybe upgrading our dependencies would help ?

Update: More clues

I cannot be 100% sure but it looks like a giget problem. I understand giget has its own dependency resolution algorithm, maybe the fact that the issue only appears in workers environments is a hint that giget cannot resolve the correct version of node-fetch-native there.

Baroshem commented 5 months ago

Thanks @unr and @vejja for additional details.

I think that we would need a help from @pi0 here :)

vejja commented 5 months ago

Thanks @unr and @vejja for additional details.

I think that we would need a help from @pi0 here :)

Yes, definitely

In the meantime, would @unr be ok to try upgrading nuxt to 3.9.1 ? The fact that pnpm-lock.yaml was upgraded there might help giget to find node-fetch-native

unr commented 5 months ago

@vejja I tried the same thing with nuxt 3.9.1, gives me the same error, sorry. :(

1mak commented 5 months ago

I am seeing the exact same issue with nuxt 3.9.1 and nuxt 3.9.1 using cloudflare pages. I also thought it's a dependency mismatch between node-fetch-native 1.4.1 and 1.6.1 but I could be wrong.

Edit: I don't think this issue is related to nuxt-security as I don't have this plugin installed.

Baroshem commented 5 months ago

Hey @1mak

Thanks for reporting that! I dont think it is related to NuxtSecurity either (at least the core functionality) but more about its dependencies (giget) or dependency missmatch. I will await for @pi0 here to help us as giget is a package from unjs

vejja commented 5 months ago

@Baroshem I am submitting a PR that updates our yarn.lock file in an attempt to solve the issue temporarily for our CF users. We don't know whether giget and node-fetch-native are responsible for the bug but we can try this fix.

The issue we are facing is that we can't properly test this hypothesis before you publish to npm. So if you want to try this fix, would need to release a 1.0.1 and push it to npm first, and then users can let us know if this solves the issue.

Not a clean way to work, but couldn't think of a better way to try fixing

pi0 commented 5 months ago

https://github.com/unjs/giget/issues/140#issuecomment-1884634195 . renewing lockfile should solve the hoisting issue.

But I think something else is wrong. nighter giget or node-fetch-native are supposed to be bundled that lead to the originally reported issue.

Is there any runnable Nuxt project to reproduce this issue? I would be happy to investigate if you can provide one 🙏🏼

vejja commented 5 months ago

@unr @nicgene @1mak : Would any of you guys be able to provide a repro to @pi0 ? See his comment above

Baroshem commented 5 months ago

@vejja @pi0

Thanks for your input. Let's wait some time for guys who reported the issue for reproduction maybe so that we can avoid publishing a new version that wont fix an issue but could break something else :)

unr commented 5 months ago

Hey @pi0 I've created a minimal reproduction here.

I've setup an empty nuxt 3.9.1 project, add nuxt security and some basic configs.

There is a GH Action that runs the build for NITRO_PRESET=cloudflare_pages

The build fails on GH Actions.

Example Project, PR that fails to build

Failing Build GH Action here

1mak commented 5 months ago

@unr that's the exact same build error I got in the cloudflare pages console, although I don't have the nuxt-security package installed. Do you get the same error when you uninstall the package or does the error go away?

image
Baroshem commented 5 months ago

@pi0 do you have any clues? As @1mak pointed, the issue appears also on project that does not have nuxt-security.

Maybe it is caused by a preset?

unr commented 5 months ago

I wonder what other package causes it for you @1mak

On my example project, if I remove nuxt-security it works fine.

https://github.com/unr/nuxt-security-failed-deploy-example/pull/2

pi0 commented 5 months ago

Issue is with nuxt-security module in /src/runtime/nitro/plugins/05-cspSsgPresets.ts#L2 you should never ever import @nuxt/kit or nuxt builder dependencies in runtime. It will cause part of Nuxt to build dependencies (including giget that is not even meant for runtime) to be bundled and in workers, causing this issue.

/cc @danielroe it happened again... I will try to check import protection. (~> https://github.com/nuxt/nuxt/pull/25162)

1mak commented 5 months ago

Thanks to your comment @pi0 I was able to make the right assumptions when looking through my package.json. Looks like the culprit was a plugin to generate sitemaps (nuxt-simple-sitemap, https://www.npmjs.com/package/nuxt-simple-sitemap, v3.1.7) which worked fine with nuxt 3.8.4 but caused the build error with cloudflare in nuxt 3.9.1. The simple fix was to bump this package up to its latest version 5.0.1 (they've also renamed it to @nuxtjs/sitemap).

Thanks again everyone for your help on this, even though your work wasn't causing the bug at all. It also made me aware that your package exists. :)

vejja commented 5 months ago

@Baroshem we can remove 05-cspSsgPresets.ts, it is not a critical component of the module It is only used to generate headers for static SSG nitro presets

Baroshem commented 5 months ago

@vejja

I have been thinking more about maybe refactoring the implementation to not remove a useful functionality.

@pi0 do you know if there is a way to refactor this preset plugin for nitro so that it wont break the deployment in cloudflare but will still make it work?

pi0 commented 5 months ago

useNitro() is available as an auto import.

vejja commented 5 months ago

useNitro() is available as an auto import.

Hi @pi0 I can't import useNitro(), is there something specific I should do ?

Capture d’écran 2024-01-15 à 12 24 02

FYI we have

vejja commented 5 months ago

@vejja

I have been thinking more about maybe refactoring the implementation to not remove a useful functionality.

@pi0 do you know if there is a way to refactor this preset plugin for nitro so that it wont break the deployment in cloudflare but will still make it work?

Hi @Baroshem I think a full refactoring is required. However I do think that #298 lay the proper foundations for that. I need to better understand what @huang-julien is doing with the context, I'll have a deeper look

Baroshem commented 5 months ago

Awesome @vejja

Thanks for looking into it. For now, I was not successful with trying to refactor the cspPresetPlugin to make it work without nuxt kit :(

I will try to do some coding today and tomorrow to see if I can make it work

Baroshem commented 5 months ago

Hey guys,

I have just published a 1.0.1 version where we removed the part of the code that was causing the issues. We will refactor it for the next major version that we want to release next week probably (1.1.0)

Sorry it tooked so long but we wanted to refactor the code without disabling functionality but we didnt make it so we will do it in the next release.

Could you please verify if the issue is gone?

Another issue related to this code was fixed in 1.0.1 image

unr commented 5 months ago

@Baroshem Thank you for this, I can confirm my build now works with 1.0.1

Baroshem commented 5 months ago

Thank you @vejja :)

danielroe commented 5 months ago

useNitro is not a runtime utility - it's a nuxt/kit utility meant to be used at build-time in a Nuxt module.

useNitroApp is an auto-imported nitro utility.

pi0 commented 5 months ago

I think it is probably safest that you disable this flag in meantime. CSP should ideally come to the nitro/nuxt core for proper support in all conditions.

I also made an upstream idea in nitro https://github.com/unjs/nitro/issues/2119 that it can allow same solution you currently do, little more generic so similar usecases can leverage.

Otherwise @danielroe is correct, useNitro is build time and useNitroApp is runtime.

Baroshem commented 5 months ago

Thanks @danielroe @pi0

I tried using useNitroApp and it is available but I wonder if it is possible to access routeRules from it?

The plugin (you said flag Pooya) is already disabled in 1.0.1 version to unblock people in this thread but I wanted to publish 1.1.0 next week with a fix for this plugin so that it can appear again. But from what I understand, it is better to remove it and wait for the nitro replacement, am I right?