-
Notifications
You must be signed in to change notification settings - Fork 3
ci: add-fixtures-and-generate-bundles #627
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import { davinci } from '@forgerock/davinci-client'; | ||
|
|
||
| const client = await davinci({ | ||
| config: { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| clientId: 'test-client', | ||
| redirectUri: 'https://example.com/callback', | ||
| scope: 'openid profile', | ||
| }, | ||
| }); | ||
|
|
||
| let node = await client.start(); | ||
|
|
||
| // Walk the flow until it reaches a terminal node | ||
| while (node.status === 'continue') { | ||
| for (const collector of node.collectors) { | ||
| if (collector.category === 'SingleValueCollector' && collector.type === 'TextCollector') { | ||
| client.update(collector)('test-value'); | ||
| } | ||
| if (collector.category === 'SingleValueCollector' && collector.type === 'PasswordCollector') { | ||
| client.update(collector)('test-password'); | ||
| } | ||
| } | ||
| node = await client.next(); | ||
| } | ||
|
|
||
| if (node.status === 'success') { | ||
| console.log('Login successful', node.session); | ||
| } else if (node.status === 'error' || node.status === 'failure') { | ||
| console.error('Login failed', node.error); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { davinci } from '@forgerock/davinci-client'; | ||
|
|
||
| const client = await davinci({ | ||
| config: { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| clientId: 'test-client', | ||
| redirectUri: 'https://example.com/callback', | ||
| scope: 'openid profile', | ||
| }, | ||
| }); | ||
|
|
||
| const node = await client.start(); | ||
| console.log(node); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { deviceClient } from '@forgerock/device-client'; | ||
|
|
||
| const client = deviceClient({ | ||
| serverConfig: { | ||
| baseUrl: 'https://example.com/am', | ||
| }, | ||
| realmPath: 'root', | ||
| }); | ||
|
|
||
| // Retrieve OATH (TOTP/HOTP) devices for a user | ||
| const oathDevices = await client.oath.get({ | ||
| userId: 'user@example.com', | ||
| }); | ||
| console.log(oathDevices); | ||
|
|
||
| // Retrieve Push notification devices | ||
| const pushDevices = await client.push.get({ | ||
| userId: 'user@example.com', | ||
| }); | ||
| console.log(pushDevices); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // Same usage but imports from the top-level 'effect' barrel instead of 'effect/Option' | ||
| // Tests whether the barrel import prevents tree-shaking vs the subpath | ||
| import { Option, pipe } from 'effect'; | ||
|
|
||
| const result = pipe( | ||
| Option.fromNullable(Math.random() > 0.5 ? 'hello' : null), | ||
| Option.match({ | ||
| onNone: () => 'none', | ||
| onSome: (v) => v.toUpperCase(), | ||
| }), | ||
| ); | ||
|
|
||
| console.log(result); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,14 @@ | ||||||||||||||||||||||||||||||||||||||
| // Imports Option via the subpath: effect/Option | ||||||||||||||||||||||||||||||||||||||
| // Tests whether Rollup tree-shakes to only fromNullable + match | ||||||||||||||||||||||||||||||||||||||
| import * as Option from 'effect/Option'; | ||||||||||||||||||||||||||||||||||||||
| import { pipe } from 'effect/Function'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const result = pipe( | ||||||||||||||||||||||||||||||||||||||
| Option.fromNullable(Math.random() > 0.5 ? 'hello' : null), | ||||||||||||||||||||||||||||||||||||||
| Option.match({ | ||||||||||||||||||||||||||||||||||||||
| onNone: () => 'none', | ||||||||||||||||||||||||||||||||||||||
| onSome: (v) => v.toUpperCase(), | ||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Yes, in Rollup tree-shaking, Citations:
🏁 Script executed: # Check if the file exists and view its current content
cat -n e2e/bundle-check-app/fixtures/effect-subpath-option.tsRepository: ForgeRock/ping-javascript-sdk Length of output: 559 🏁 Script executed: # List other fixture files to see if there's a pattern
ls -la e2e/bundle-check-app/fixtures/Repository: ForgeRock/ping-javascript-sdk Length of output: 1376 🏁 Script executed: cat -n e2e/bundle-check-app/fixtures/effect-barrel-option.tsRepository: ForgeRock/ping-javascript-sdk Length of output: 556 Use named imports to ensure accurate tree-shaking measurements for this subpath fixture. The file's comment states it tests whether Rollup tree-shakes to only Proposed change-import * as Option from 'effect/Option';
+import { fromNullable, match } from 'effect/Option';
import { pipe } from 'effect/Function';
const result = pipe(
- Option.fromNullable(Math.random() > 0.5 ? 'hello' : null),
- Option.match({
+ fromNullable(Math.random() > 0.5 ? 'hello' : null),
+ match({
onNone: () => 'none',
onSome: (v) => v.toUpperCase(),
}),
);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| console.log(result); | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { Device } from '@forgerock/journey-client/device'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| const step = await client.start(); | ||
|
|
||
| if (step.type === 'Step') { | ||
| const device = new Device(); | ||
| const profile = await device.getProfile({ collectLocation: false }); | ||
| console.log(profile); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { Policy } from '@forgerock/journey-client/policy'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| const step = await client.start(); | ||
|
|
||
| if (step.type === 'Step') { | ||
| const errors = Policy.parseErrors(step.callbacks); | ||
| console.log(errors); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { QRCode } from '@forgerock/journey-client/qr-code'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| const step = await client.start(); | ||
|
|
||
| if (step.type === 'Step') { | ||
| const qrCode = QRCode.getQRCodeData(step); | ||
| console.log(qrCode); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { RecoveryCodes } from '@forgerock/journey-client/recovery-codes'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| const step = await client.start(); | ||
|
|
||
| if (step.type === 'Step') { | ||
| const codes = RecoveryCodes.getCodes(step); | ||
| console.log(codes); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { WebAuthn, WebAuthnStepType } from '@forgerock/journey-client/webauthn'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| let step = await client.start(); | ||
|
|
||
| while (step.type === 'Step') { | ||
| const stepType = WebAuthn.getWebAuthnStepType(step); | ||
| if (stepType === WebAuthnStepType.Authenticate || stepType === WebAuthnStepType.Register) { | ||
| await WebAuthn.getWebAuthnOutcome(step); | ||
| } | ||
| step = await client.next(step); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| let step = await client.start(); | ||
|
|
||
| while (step.type === 'Step') { | ||
| if (step.callbacks.some((cb) => cb.type === 'RedirectCallback')) { | ||
| await client.redirect(step); | ||
| break; | ||
| } | ||
| step = await client.next(step); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /** | ||
| * Realistic consumer pattern: journey authentication + WebAuthn + device fingerprinting. | ||
| * Mirrors what a real app would import for a complete login experience. | ||
| */ | ||
| import { journey } from '@forgerock/journey-client'; | ||
| import { WebAuthn } from '@forgerock/journey-client/webauthn'; | ||
| import { Device } from '@forgerock/journey-client/device'; | ||
|
|
||
| const config = { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| }; | ||
|
|
||
| // Collect device profile before authentication | ||
| const device = new Device(); | ||
| const profile = await device.getProfile({ location: false, metadata: false }); | ||
| console.log('device profile collected', profile); | ||
|
|
||
| const client = await journey({ config }); | ||
| let step = await client.start(); | ||
|
|
||
| while (step.type === 'Step') { | ||
| // Check if this step requires WebAuthn | ||
| const webAuthnType = WebAuthn.getWebAuthnStepType(step); | ||
| if (webAuthnType !== 'None') { | ||
| console.log('webauthn step type', webAuthnType); | ||
| } | ||
|
|
||
| step = await client.next(step); | ||
| } | ||
|
|
||
| if (step.type === 'LoginSuccess') { | ||
| console.log('authenticated', step.getSessionToken()); | ||
| } else if (step.type === 'LoginFailure') { | ||
| console.error('authentication failed', step); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { oidc } from '@forgerock/oidc-client'; | ||
|
|
||
| const client = await oidc({ | ||
| config: { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| clientId: 'test-client', | ||
| redirectUri: 'https://example.com/callback', | ||
| scope: 'openid profile', | ||
| }, | ||
| }); | ||
|
|
||
| if ('error' in client) { | ||
| console.error(client.error); | ||
| } else { | ||
| // Revoke tokens (server-side invalidation) | ||
| const revokeResult = await client.token.revoke(); | ||
| console.log(revokeResult); | ||
|
|
||
| // Full logout (revoke + end session endpoint) | ||
| const logoutResult = await client.logout(); | ||
| console.log(logoutResult); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import { oidc } from '@forgerock/oidc-client'; | ||
|
|
||
| const client = await oidc({ | ||
| config: { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| clientId: 'test-client', | ||
| redirectUri: 'https://example.com/callback', | ||
| scope: 'openid profile', | ||
| }, | ||
| }); | ||
|
|
||
| if ('error' in client) { | ||
| console.error(client.error); | ||
| } else { | ||
| // Token exchange after authorization code callback | ||
| const tokens = await client.token.exchange('auth-code-123', 'state-abc'); | ||
| if ('error' in tokens) { | ||
| console.error(tokens.error); | ||
| } else { | ||
| console.log(tokens); | ||
| } | ||
|
|
||
| // Retrieve stored tokens (with auto-renew if backgroundRenew is set) | ||
| const stored = await client.token.get({ backgroundRenew: false }); | ||
| if ('error' in stored) { | ||
| console.error(stored.error); | ||
| } else { | ||
| console.log(stored); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { oidc } from '@forgerock/oidc-client'; | ||
|
|
||
| const client = await oidc({ | ||
| config: { | ||
| serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, | ||
| clientId: 'test-client', | ||
| redirectUri: 'https://example.com/callback', | ||
| scope: 'openid profile', | ||
| }, | ||
| }); | ||
|
|
||
| const url = await client.getAuthorizationUrl(); | ||
| console.log(url); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { protect } from '@forgerock/protect'; | ||
|
|
||
| const api = protect({ | ||
| envId: 'example-env-id', | ||
| behavioralDataCollection: true, | ||
| }); | ||
|
|
||
| const startResult = await api.start(); | ||
|
|
||
| if (startResult && 'error' in startResult) { | ||
| console.error(startResult.error); | ||
| } else { | ||
| const data = await api.getData(); | ||
| console.log(data); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import { journey } from '@forgerock/journey-client'; | ||
|
|
||
| const client = await journey({ | ||
| config: { serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' } }, | ||
| }); | ||
|
|
||
| const step = await client.start(); | ||
|
|
||
| if (step.type === 'Step') { | ||
| await client.redirect(step); | ||
| } |
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.
🧩 Analysis chain
🌐 Web query:
Foractions/upload-artifact@v5, what is the default behavior ofif-no-files-found, and does it fail the workflow by default?💡 Result:
The default behavior of
if-no-files-foundforactions/upload-artifact@v5is 'warn', which outputs a warning but does not fail the action or the workflow.[1][2][3][4] It does not fail the workflow by default; the action succeeds with a warning when no files are found.[1][5]Citations:
Add
if-no-files-found: errorto fail fast when the feature baseline file is missing.The default
if-no-files-foundbehavior iswarn, which allows the action to succeed silently if the baseline JSON is absent. This breaks the CI invariant that the baseline must exist for downstream comparisons. Setting it toerrorensures the workflow fails immediately if the file is not generated.Proposed change
- name: Upload feature bundle baseline uses: actions/upload-artifact@v5 with: name: bundle-feature-baseline path: e2e/bundle-check-app/dist/bundle-feature-baseline.json + if-no-files-found: error retention-days: 30🤖 Prompt for AI Agents