Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
7 changes: 6 additions & 1 deletion src/commands/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,10 @@ export default class BaseCommand extends Command {
siteData = result
}

if (siteData.id) {
actionCommand.siteId = siteData.id
}

const globalConfig = await getGlobalConfigStore()

// ==================================================
Expand Down Expand Up @@ -769,10 +773,11 @@ export default class BaseCommand extends Command {
root: buildDir,
configPath,
get id() {
return state.get('siteId')
return actionCommand.siteId || state.get('siteId')
},
set id(id) {
state.set('siteId', id)
actionCommand.siteId = id
Comment on lines +776 to +780
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't let netlify.site.id return an unresolved site name.

Line 772 now prefers actionCommand.siteId, but that field is seeded from both --site and --site-id. In this file, only flags.site goes through the later getSiteByName() fallback, so --site-id my-site-name can still make netlify.site.id return "my-site-name" instead of the canonical site ID. That means the new alias will still fail anywhere downstream expects an actual ID.

Suggested fix
-    let siteData = siteInfo
-    if (!siteData.url && flags.site) {
-      const result = await getSiteByName(api, flags.site)
+    let siteData = siteInfo
+    const siteSelector =
+      typeof flags.siteId === 'string' ? flags.siteId : typeof flags.site === 'string' ? flags.site : undefined
+    if (!siteData.url && siteSelector) {
+      const result = await getSiteByName(api, siteSelector)
       if (result == null) {
-        return logAndThrowError(`Project with name "${flags.site}" not found`)
+        return logAndThrowError(`Project with name "${siteSelector}" not found`)
       }
       siteData = result
+      actionCommand.siteId = result.id
     }
         get id() {
-          return actionCommand.siteId || state.get('siteId')
+          return siteData?.id || actionCommand.siteId || state.get('siteId')
         },
πŸ€– Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/base-command.ts` around lines 772 - 776, The getter for
netlify.site.id currently returns actionCommand.siteId first, which can contain
an unresolved site name seeded from --site or --site-id; change the logic so the
canonical ID from state.get('siteId') is preferred (state.get('siteId') ||
actionCommand.siteId) or ensure any assignment to actionCommand.siteId (from
flags.site or flags['site-id']) is normalized by calling getSiteByName(...) and
storing the resolved site.id before returning; update the getter and the code
path that sets actionCommand.siteId (or the setter id) so actionCommand.siteId
never holds an unresolved site name.

},
},
// Site information retrieved using the API (api.getSite())
Expand Down
5 changes: 5 additions & 0 deletions src/commands/env/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const createEnvCommand = (program: BaseCommand) => {
)
.option('--json', 'Output environment variables as JSON')
.option('--site <name-or-id>', 'A project name or ID to target')
.addOption(new Option('--site-id <name-or-id>').hideHelp(true))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.addOption(
new Option('-s, --scope <scope>', 'Specify a scope')
.choices(['builds', 'functions', 'post-processing', 'runtime', 'any'])
Expand Down Expand Up @@ -47,6 +48,7 @@ export const createEnvCommand = (program: BaseCommand) => {
)
.option('--json', 'Output environment variables as JSON')
.option('-s, --site <name-or-id>', 'A project name or ID to target')
.addOption(new Option('--site-id <name-or-id>').hideHelp(true))
.description('Import and set environment variables from .env file')
.action(async (fileName: string, options: OptionValues, command: BaseCommand) => {
const { envImport } = await import('./env-import.js')
Expand All @@ -63,6 +65,7 @@ export const createEnvCommand = (program: BaseCommand) => {
)
.option('--json', 'Output environment variables as JSON')
.option('--site <name-or-id>', 'A project name or ID to target')
.addOption(new Option('--site-id <name-or-id>').hideHelp(true))
.addOption(new Option('--plain', 'Output environment variables as plaintext').conflicts('json'))
.addOption(
new Option('-s, --scope <scope>', 'Specify a scope')
Expand Down Expand Up @@ -94,6 +97,7 @@ export const createEnvCommand = (program: BaseCommand) => {
)
.option('--json', 'Output environment variables as JSON')
.option('--site <name-or-id>', 'A project name or ID to target')
.addOption(new Option('--site-id <name-or-id>').hideHelp(true))
.addOption(
new Option('-s, --scope <scope...>', 'Specify a scope (default: all scopes)').choices([
'builds',
Expand Down Expand Up @@ -131,6 +135,7 @@ export const createEnvCommand = (program: BaseCommand) => {
)
.option('--json', 'Output environment variables as JSON')
.option('-s, --site <name-or-id>', 'A project name or ID to target')
.addOption(new Option('--site-id <name-or-id>').hideHelp(true))
.addExamples([
'netlify env:unset VAR_NAME # unset in all contexts',
'netlify env:unset VAR_NAME --context production',
Expand Down
Loading