Skip to content

fix(auth): add dynamic auth providers - #151

Merged
jrichter1 merged 1 commit into
redhat-developer:mainfrom
JessicaJHee:add-auth-provider
Aug 22, 2026
Merged

fix(auth): add dynamic auth providers#151
jrichter1 merged 1 commit into
redhat-developer:mainfrom
JessicaJHee:add-auth-provider

Conversation

@JessicaJHee

Copy link
Copy Markdown
Member

Summary

  • Guest, GitHub, and Keycloak (OIDC) auth profiles now enable the matching auth-backend provider plugins. Those providers are no longer installed statically in RHDH, so tests that only set auth: would boot without a sign-in provider.
  • Guest and GitHub gain a dynamic-plugins.yaml; the Keycloak profile adds oidc-provider (sign-in stays stock OIDC against the Keycloak IdP).

Next Steps plan

  • Update Overlay backstage e2e tests against this version in this PR
  • Migrate to keycloak auth provider from stock OIDC after we migrate to NFS

Signed-off-by: Jessica He <jhe@redhat.com>
@jrichter1
jrichter1 merged commit cbb299e into redhat-developer:main Aug 22, 2026
3 checks passed
gustavolira added a commit that referenced this pull request Aug 24, 2026
#151 merged today and claimed 2.1.10, so the renumber in the previous commit
collided with main and the Version Bump Check would have refused it. Same number
as before, different reason: this is no longer about #149, which now bumps
nothing at all.

Worth noting separately: main says 2.1.10 but the publish workflow for it failed,
so npm latest is still 2.1.9. If that is not resolved before this merges, 2.1.11
publishes over a 2.1.10 that never existed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gustavolira added a commit that referenced this pull request Aug 24, 2026
The PR was DIRTY, which is why GitHub had stopped running checks on it — a pull
request that cannot be merged gets no merge commit to test, so the last two
pushes produced zero check runs and looked like CI hanging.

Both conflicts were version bookkeeping from #151: package.json keeps 2.1.11,
and its 2.1.10 section moves below ours in the changelog rather than competing
for "Current". #151 also touched deployment.ts, which this branch changes, but
git merged those cleanly and the suite is green.

141 tests pass, yarn check clean, docs build clean.
subhashkhileri pushed a commit that referenced this pull request Aug 26, 2026
…oting legacy (#152)

* fix(nfs): make a lane that is not actually running NFS fail instead of pass

Three defects found while triaging the overlay migration, all with the same
shape: the harness cannot tell a working NFS lane from one that quietly fell
back to the legacy shell.

RHIDP-16457 — a workspace could disable the NFS it asked for. The NFS secret
layer merges before the workspace's own tests/config/rhdh-secrets.yaml, so a
workspace setting APP_CONFIG_app_packageName or ENABLE_STANDARD_MODULE_FEDERATION
for its own reasons overrode it. Nothing then failed: the legacy suite re-ran
and passed, and the only thing the lane existed to prove was never exercised.
deploy() now checks the merged secret still carries both markers and throws
naming the key, the value found, and the file responsible. The merge order is
untouched — a workspace has to be able to override defaults, which is exactly
why the outcome needs checking rather than assuming.

Also from RHIDP-16457, and from RHIDP-16461: configure() now logs which of the
three mechanisms decided the shell, because none of them is visible from a
single file and the answer currently requires reading a project name, an
environment variable and a configure() call together. A namespace ending in
-app-next that was explicitly configured with useNewFrontendSystem: false warns,
since it deploys legacy under a name that reads as NFS everywhere. Only that
direction is checked: enabling NFS without the suffix is legitimate and is what
github and homepage do.

RHIDP-16459 — the GitHub session file was a bare relative authState_<user>.json,
resolved against process.cwd(), which the worker fixture sets to the same
workspace directory for every project. A workspace's lanes shared one file per
user, unlocked: one lane could inject another's storage state, and a reader
landing mid-write died on truncated JSON as a flake that looked nothing like the
plugin under test. Every lane added is another writer. The path is now absolute
and keyed by project as well as user, the write goes through a temp file and a
rename, and an unusable session falls through to a full login rather than
throwing.

RHIDP-16458 — SidebarTabs hardcoded "Self-service", which is the legacy shell's
scaffolder title; under app-next the page is "Create", so a spec running there
could not type-check without a cast. Both are members now. Deliberately only
that: which label a lane should use is RHIDP-16462, three workarounds are in
flight for it, and picking one here would be a fourth.

All four new behaviours are mutation-tested — reverting each turns the matching
tests red and nothing else. 136 tests pass; typecheck, eslint and prettier are
clean; the docs build validates its own links.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(nfs): the session fix would have caused the failure it prevents

Review found two of the three changes wrong in ways the tests did not reach.

Keying the GitHub session file per project removed cross-lane sharing, which is
what the ticket asked for — and would have made every lane of a workspace log in
to the same GitHub account concurrently. logintoGithub derives its 2FA code from
one shared TOTP secret, so lanes starting inside the same 30-second window submit
the identical code and GitHub rejects the second. This file already carries retry
handling for exactly that error, which is how it is known to happen; bulk-import
would have gone from one login to three simultaneous ones.

So the file is one per user again, and what was actually missing is added
instead: a lock spanning read-or-login-and-write, not just the write, because two
lanes that both decide there is no session go on to log in anyway. RHDH cookies
from another lane were never the hazard — each lane's RHDH lives on its own
namespace hostname.

The [nfs] line was logged from configure(), but the worker fixture calls
configure() with no arguments for every project before any spec runs. For github
and homepage — the two lanes the change was written for, which opt in through
configure({ useNewFrontendSystem: true }) — the first line said "off, from
nothing", and the first line is the one a reader greps. Reported from deploy()
now, once, after configuration is final.

Two smaller ones. The guard accepted an unquoted YAML `true` by coercing in the
comparison only, so it green-lit a payload the API server rejects with "cannot
unmarshal bool into Go struct field ... of type string" — an opaque k8s failure
in place of the guard's own message. It now rewrites the value as well. And the
temp file survived a failed storageState write, accumulating untracked
authState*.tmp files in a directory nothing gitignores them from.

New tests for the lock, both write outcomes, and the boolean rewrite; the
serialisation test waits for the first holder rather than racing two callers
from the same tick, which was flaky. Mutation-tested: removing the lock, the
temp-file cleanup, or the in-place coercion each turns exactly one test red.
141 pass, five consecutive runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: take 2.1.10, now that #149 claims no version

#149 was reduced to a documentation change, so it no longer bumps the version and
2.1.10 is free. The note about the two PRs colliding goes with it — there is only
one version-bumping PR open now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: back to 2.1.11 — main took 2.1.10

#151 merged today and claimed 2.1.10, so the renumber in the previous commit
collided with main and the Version Bump Check would have refused it. Same number
as before, different reason: this is no longer about #149, which now bumps
nothing at all.

Worth noting separately: main says 2.1.10 but the publish workflow for it failed,
so npm latest is still 2.1.9. If that is not resolved before this merges, 2.1.11
publishes over a 2.1.10 that never existed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(nfs): the deployment guide said the workspace secret always wins

It does not any more, and the guide said it in as many words: "your
rhdh-secrets.yaml still wins on conflicts". True for every key except the two
NFS markers, where overriding now throws instead of quietly deploying the legacy
shell — so the sentence this PR contradicts is corrected in the same change
rather than left to be discovered from a stack trace.

Also documented, because a new hard failure with no docs costs someone an hour:
the `[nfs]` line and what to grep for when a lane behaves like the wrong shell,
why it comes from deploy() rather than configure(), the exact throw and the fact
that it is a post-condition on the caller's own config, and the -app-next
namespace warning together with why the reverse is not checked.

The dynamic-plugins layer is named as the unguarded one. Disabling app-auth or
app-integrations from a workspace's own dynamic-plugins.yaml degrades the lane
the same silent way, and nothing catches it. No workspace does that today — 14
ship their own dynamic-plugins.yaml and none names either package — so a second
guard would be insurance against something nobody does, which is the argument
that just closed rhdh-plugin-export-overlays#3375. Documented instead, and it is
the first place to look when an NFS lane behaves like the legacy shell.

deploy()'s step list gains both the report and the throw.

141 tests pass, yarn check clean, docs build clean.

* fix(nfs): fail the lane on an intent conflict instead of warning about it

The guard found the conflict and then let the run continue. A lane named
<ws>-app-next configured with useNewFrontendSystem: false deployed the legacy
shell, re-ran the legacy suite, passed, and left one console.warn behind on a
run that exited 0 — which is indistinguishable from a run that had nothing to
say. That is the exact failure this module exists to stop, and the PR's own
title claims it does.

assertNfsMarkersSurvived already throws for the other path, where a workspace's
own rhdh-secrets.yaml overwrites the markers. The two paths now behave the same.

describeNfsIntentConflict stays a pure describer with its existing tests;
assertNfsIntentMatches is a thin wrapper over it so the throwing behaviour is
directly testable rather than reachable only through a private method on
RHDHDeployment. The [nfs] line is logged before the check so the resolved state
is on record even when the next line ends the run.

Mutation-verified: turning the throw back into a return fails
"fails the deploy on the conflict, rather than only naming it" and nothing else.

Closes the library half of RHIDP-16457 — bulk-import's local
expect(rhdh.deploymentConfig.useNewFrontendSystem).toBe(true) was stronger than
the library guard until now, which is the inverse of what that ticket asks for.

* fix(github-session): lock only session creation, and scope this PR to that

Two changes from review.

Lock scope. The lock spanned read-or-login-and-write, so the reuse path —
addCookies, goto, Sign In, wait for nav or popup — ran inside it too. Reuse
needs no exclusivity: the lanes are different namespace hosts and only creation
submits a TOTP. Every loginAsGithubUser therefore queued behind a sign-in it did
not need, and a waiter could exhaust Playwright's default test timeout before
proper-lockfile's own retries ran out, because test.setTimeout(260_000) is
raised inside logintoGithub — precisely the path a waiter is not on.

ensureGithubSession now checks for a session outside the lock and takes it only
to create one, re-reading inside so a caller that queued behind the lane that
created it reuses that session rather than logging in again with the same TOTP
code. loginAsGithubUser splits into _reuseGithubSession and
_createGithubSession; creation already leaves the page signed in, so the reuse
path is not replayed after it.

Mutation-verified, one test each: dropping the outer check fails "reuses an
existing session without taking the lock"; dropping the inner re-read fails
"creates once when two callers find no session at the same time".

The first version of that first test was wrong and passed under the mutation —
it started ensureGithubSession in the same tick as the lock holder, so it raced
the scheduler rather than the lock and the result depended on how loaded the run
was. It now waits until the lock is demonstrably held, and is bounded by a timer
so reintroducing the bug fails instead of deadlocking CI.

Scope. The NFS work is removed — nfs-guard, the deploy-time report and marker
check, the SidebarTabs label, and the docs for them. With the old frontend
coming out there is no legacy shell to silently fall back into, so guarding
against it earns little and would be deleted in the cleanup anyway.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants