Skip to content

Commit 43fcdb1

Browse files
Merge pull request #1020 from Max-Health-Inc/develop
🧪 Auto-PR: Merge `develop` → `test`
2 parents 1f6f883 + 68b308d commit 43fcdb1

14 files changed

Lines changed: 72 additions & 15 deletions

File tree

.github/scripts/inferno-oauth-automation.js

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,10 +766,40 @@ async function runEhrLaunchTests(sessionId, browser) {
766766
}
767767
}
768768

769+
/**
770+
* Find the authorization URL a waiting test is blocked on.
771+
*
772+
* Prefers a recorded outgoing request (an exact URL) over one parsed out of the
773+
* wait message's prose, which is how the EHR launch URL lost its query string.
774+
* Returns null if nothing looks like an authorize URL yet.
775+
*/
776+
function findAuthorizeUrl(results) {
777+
for (const result of results || []) {
778+
if (result.result !== 'wait') continue;
779+
780+
for (const req of result.requests || []) {
781+
if (req.direction === 'outgoing' && req.url && req.url.includes('authorize')) {
782+
return req.url;
783+
}
784+
}
785+
786+
for (const field of ['wait_message', 'result_message', 'messages']) {
787+
if (!result[field]) continue;
788+
const content = typeof result[field] === 'string' ? result[field] : JSON.stringify(result[field]);
789+
const match = content.match(/https?:\/\/[^\s<>"')]+?authorize[^\s<>"')]*/);
790+
if (match) return match[0].replace(/[.,;:!?]+$/, '');
791+
}
792+
}
793+
return null;
794+
}
795+
769796
/**
770797
* Wait for EHR Launch test completion.
771-
* Similar to waitForSimpleTestCompletion but looks for Inferno's launch URL
772-
* (containing /launch) instead of an authorize URL.
798+
*
799+
* Two phases, and the loop used to serve only the first: the EHR hands the app its
800+
* launch context, and THEN the app performs the authorization redirect the user has
801+
* to complete. Once `launchAttempted` was set nothing acted again, so the run sat in
802+
* `waiting` until the 3-minute timeout with `smart_app_redirect_stu2` never resolved.
773803
*/
774804
async function waitForEhrLaunchCompletion(sessionId, runId, browser) {
775805
const maxWait = 180000; // 3 minutes
@@ -778,6 +808,8 @@ async function waitForEhrLaunchCompletion(sessionId, runId, browser) {
778808
let page = null;
779809
let launchAttempted = false;
780810
let launchAttemptCount = 0;
811+
let authorizeAttempted = false;
812+
let authorizeAttemptCount = 0;
781813
const MAX_LAUNCH_ATTEMPTS = 3;
782814

783815
console.log(`Waiting for EHR Launch test run ${runId} to complete (timeout: 3 minutes)...`);
@@ -896,6 +928,31 @@ async function waitForEhrLaunchCompletion(sessionId, runId, browser) {
896928
}
897929
}
898930
}
931+
} else if (runStatus.status === 'waiting' && browser && launchAttempted && !authorizeAttempted
932+
&& authorizeAttemptCount < MAX_LAUNCH_ATTEMPTS) {
933+
// Phase 2: the app has its launch context and now redirects the user to
934+
// authorize. Same handling as the standalone group.
935+
const authUrl = findAuthorizeUrl(runStatus.results);
936+
937+
if (!authUrl) {
938+
// No URL yet is normal for a poll or two. Say what the payload holds so a
939+
// persistent stall names its own cause instead of timing out silently.
940+
const waitIds = (runStatus.results || [])
941+
.filter(r => r.result === 'wait')
942+
.map(r => r.test_id || 'unknown');
943+
console.log(` Post-launch: waiting for an authorization URL (blocked on: ${waitIds.join(', ') || 'nothing'})`);
944+
} else {
945+
authorizeAttemptCount++;
946+
console.log(` Post-launch authorization (attempt ${authorizeAttemptCount}/${MAX_LAUNCH_ATTEMPTS}): ${authUrl.substring(0, 140)}`);
947+
try {
948+
if (!page) page = await browser.newPage();
949+
await handleOAuthFlow(page, authUrl);
950+
authorizeAttempted = true;
951+
console.log(' EHR Launch authorization completed, continuing to poll...');
952+
} catch (authError) {
953+
console.error(` EHR Launch authorization failed: ${authError.message}`);
954+
}
955+
}
899956
} else if (runStatus.status === 'waiting') {
900957
if (launchAttemptCount >= MAX_LAUNCH_ATTEMPTS) {
901958
console.error(` EHR Launch OAuth failed after ${MAX_LAUNCH_ATTEMPTS} attempts — aborting wait`);

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "proxy-smart-backend",
33
"displayName": "Proxy Smart Backend",
4-
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
4+
"version": "0.3.14-alpha.202608131946.961ab42c4",
55
"type": "module",
66
"scripts": {
77
"test": "bun test --isolate",

config/eslint/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@proxy-smart/eslint-config",
3-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
3+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
44
"private": true,
55
"type": "module",
66
"exports": {

deploy/infra/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "proxy-smart-infra",
33
"displayName": "Proxy Smart Infrastructure",
44
"description": "AWS CDK infrastructure for Proxy Smart production deployment",
5-
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
5+
"version": "0.3.14-alpha.202608131946.961ab42c4",
66
"private": true,
77
"type": "module",
88
"scripts": {

frontend/smart-dicom-template/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "SMART DICOM Algorithm Template",
44
"description": "Starter kit for building SMART on FHIR imaging algorithm apps. Clone, implement your algorithm in src/algorithm.ts, and deploy as a SMART app.",
55
"private": true,
6-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
6+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
77
"type": "module",
88
"scripts": {
99
"dev": "vite --port 5180",

frontend/ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"displayName": "Proxy Smart Admin UI",
44
"description": "A web-based administration interface for managing healthcare applications and resources via Proxy Smart.",
55
"private": true,
6-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
6+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
77
"type": "module",
88
"scripts": {
99
"dev": "vite",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "proxy-smart",
3-
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
3+
"version": "0.3.14-alpha.202608131946.961ab42c4",
44
"repository": {
55
"type": "git",
66
"url": "git+https://github.com/Max-Health-Inc/proxy-smart.git"

packages/app-store/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@proxy-smart/app-store",
3-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
3+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
44
"private": false,
55
"type": "module",
66
"description": "SMART on FHIR app store — manifest discovery, visibility configuration, and registry CRUD. Framework-agnostic.",

packages/auth/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@proxy-smart/auth",
3-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
3+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
44
"private": false,
55
"type": "module",
66
"description": "SMART on FHIR STU 2.2.0 server-side authorization proxy — launch context, session management, token enrichment. Framework-agnostic, IdP-pluggable.",

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@proxy-smart/cli",
3-
"version": "0.3.14-alpha.202608131924.cfdc0c7f7",
3+
"version": "0.3.14-beta.202608131924.cfdc0c7f7",
44
"private": false,
55
"type": "module",
66
"description": "Admin CLI for the proxy-smart SMART on FHIR authorization proxy. Authenticates via Keycloak OAuth (device flow or client_credentials) and drives the admin REST API.",

0 commit comments

Comments
 (0)