Skip to content

feat(cli): run universal-portals from an embedded tool (Beta) - #1740

Open
jacobovidal wants to merge 5 commits into
feat/up-embedded-scriptfrom
feat/up-embedded-runner
Open

jacobovidal wants to merge 5 commits into
feat/up-embedded-scriptfrom
feat/up-embedded-runner

Conversation

@jacobovidal

@jacobovidal jacobovidal commented Oct 26, 2026 •

Copy link
Copy Markdown

🔧 Changes

Third of three stacked PRs (on #1739). auth0 universal-portals setup and the new audit now run the Universal Portals tool that is built into the binary, instead of the Go code that was here.

  • How it works. The command writes the embedded JavaScript file to a private temporary file (folder 0700, file 0600, removed afterwards), runs it with Node.js, hands over the terminal and returns its exit code. The tool reaches the Management API by calling this same CLI (auth0 api), so the login and the token stay inside the CLI. It lets the tool finish its own message on Ctrl+C instead of exiting at once (the same pattern as acul dev).
  • Flags are not parsed by the CLI. Every argument goes to the tool, which has its own --help. So the setup page in docs/ no longer has a flag table, and the new audit page has none.
  • Removed. The old 1048-line runner, and the three helpers it alone used in utils_shared.go (missingScopes, scopesFromToken, deriveServiceURL).
  • Guards. A test fails if the embedded file is older than its sources (the hash definition is pinned by a hand-computed value that the tool's tests check too). Another fails if plugins.go appears in this folder: see below.
  • Docs regenerated with make docs.

Behaviour changes for people using the current beta command

  • Node.js 20.12 or newer is required (ACUL already needs Node.js on this branch).
  • A rerun reuses what exists instead of creating duplicates, and the flags --name and --slug still work.
  • The portal application no longer gets a Management API grant or the client_credentials grant type. The forms use a separate, minimal application. Portals created by the old command get audit findings P010 and P011 for this.
  • New: --template business with a test user and organization, audit with --fix, --strict and --organization, and --json.

This is temporary. The header of universal_portals.go lists what to delete when the plugin framework can install the tool. The framework skips a plugin whose name matches a built-in command, which is why the second guard exists.

Known limits: the command needs the CLI to be logged in even for --help; Windows is not tested. Flag parsing is off, so the CLI's own login check does not see --tenant or --no-input when they come after the subcommand: it checks the active tenant, and with an expired session it can offer to log in instead of failing. The tool then uses the tenant from --tenant. The missing-Node message is worded for this command and differs from the one ACUL shows. When the tool ends with a non-zero code, the launcher exits directly, so that run is not counted by the CLI's usage tracking. Ctrl+C: the tool decides, and a tool ended by the signal is reported as exit code 130, unlike the rest of this branch where the root handler exits 0.

📚 References

Stacked on #1739. Related: the plugin framework PRs, which this stands in for until they are available on this branch.

🔬 Testing

make test-unit      # includes the new tests, with the race detector
make docs           # regenerates the command pages; check-docs is clean

New tests cover the launcher with a fake node (arguments, environment, private temporary file, terminal input, exit code, Ctrl+C) and one test that runs the embedded file under the real Node.js.

By hand, with a binary built from this branch against a development tenant: audit of two existing portals, consumer setup plus a second run, business setup by email, and audit of each new portal; everything created was deleted and checked. Not tested here: interactive prompts in a real terminal, and Ctrl+C in the middle of a call.

📝 Checklist

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

🤖 Generated with Claude Code

jacobovidal and others added 5 commits October 26, 2026 18:51
Replace the Go setup command with a launcher for the Universal Portals
setup and audit tool, which is built into the binary as one JavaScript
file and run with Node.js 20.12 or newer. The tool covers what the old
command did and more: business portals, reuse on a second run, an
audit with fixes, and JSON output.

The tool reaches the Management API by calling this CLI again, so the
login and the token stay inside the CLI. The launcher passes the path
of the CLI and the tenant, writes the tool to a private temporary file
that is removed afterwards, hands over the terminal, and returns the
tool's exit code. It lets the tool finish its own message on Ctrl+C
instead of exiting at once.

Flags are not parsed by the CLI: every argument goes to the tool, which
has its own help. The old runner and the three helpers only it used
are removed.

The command is temporary and its header comment lists what to delete
when the plugin framework takes over.

Co-Authored-By: Claude <noreply@anthropic.com>
The binary ships the embedded JavaScript file, so a file older than
its sources would ship old code. A test recomputes a hash of the
lockfile, the build script and the sources, and compares it with the
hash the build wrote into the first lines of the file. The hash
definition is pinned with a hand-computed value that the tool's own
tests check too, so the two implementations cannot drift apart.

A second test fails if plugins.go appears in this folder. The plugin
framework skips a plugin whose name matches a built-in command, so
once the framework is here the embedded command has to go first, and
the message points at the list of what to delete.

Co-Authored-By: Claude <noreply@anthropic.com>
Run `make docs` for the new universal-portals commands. The setup page
no longer lists flags, because the tool handles them and shows them with
--help. The audit command has a new page.

Co-Authored-By: Claude <noreply@anthropic.com>
Remove an exit hook that no test replaced, and the second Node probe.
The command asked ACUL's check whether node runs, then looked it up on
the PATH again and checked its version, so Node was started twice and
the lookup error could not be reached. ACUL's message also asked for
Node v22, but this command runs on 20.12.

Now there is one lookup and one version check, and the message names
the version this command needs. A test covers the missing-Node case.
The header comment is shorter and keeps only what is needed to remove
the command.

Co-Authored-By: Claude <noreply@anthropic.com>
The test sent SIGINT after a fixed 200 ms, which could land before
the fake tool had started on a slow machine. The tool now creates a
marker file when it starts and waits for the test to release it, so
the signal always arrives while the tool is running.

Also rename the tripwire test so no Go name mentions a plugin.

Co-Authored-By: Claude <noreply@anthropic.com>

This branch has not been deployed

No deployments
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