Skip to content

Commit 4eaa65c

Browse files
committed
fix(ci): stabilize local idp smoke checks
1 parent 4bf7c81 commit 4eaa65c

6 files changed

Lines changed: 165 additions & 68 deletions

File tree

ansible/site.yml

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -272,31 +272,24 @@
272272
until: terrarium_post_proxy_sync.rc == 0
273273
changed_when: false
274274

275-
- name: Remove local auth bootstrap TLS material before requesting public TLS
275+
- name: Remove local auth bootstrap routes before requesting public TLS
276276
ansible.builtin.file:
277277
path: "{{ item }}"
278278
state: absent
279279
loop:
280-
- "{{ terrarium_traefik_config_dir }}/dynamic/bootstrap-cert.yml"
281280
- "{{ terrarium_traefik_config_dir }}/dynamic/bootstrap-routes.yml"
282-
- "{{ terrarium_traefik_config_dir }}/bootstrap-certs"
283-
- /usr/local/share/ca-certificates/terrarium-bootstrap.crt
284-
register: terrarium_bootstrap_tls_removed
281+
register: terrarium_bootstrap_routes_removed
285282
when:
286283
- terrarium_idp_mode == 'local'
287284
- terrarium_auth_domain | default('') | length > 0
288285

289-
- name: Refresh system CA certificates after retiring bootstrap TLS
290-
ansible.builtin.command: update-ca-certificates
291-
when: terrarium_bootstrap_tls_removed is changed
292-
293-
- name: Restart Traefik after retiring bootstrap TLS
286+
- name: Restart Traefik after removing bootstrap routes
294287
ansible.builtin.systemd:
295288
name: traefik
296289
state: restarted
297-
when: terrarium_bootstrap_tls_removed is changed
290+
when: terrarium_bootstrap_routes_removed is changed
298291

299-
- name: Wait for local auth domain to serve public TLS
292+
- name: Wait for local auth domain to serve trusted TLS
300293
ansible.builtin.command:
301294
argv:
302295
- curl
@@ -310,27 +303,27 @@
310303
- --max-time
311304
- "20"
312305
- "https://{{ terrarium_auth_domain }}/.well-known/openid-configuration"
313-
register: terrarium_auth_public_tls
306+
register: terrarium_auth_trusted_tls
314307
retries: 36
315308
delay: 10
316-
until: terrarium_auth_public_tls.rc == 0
309+
until: terrarium_auth_trusted_tls.rc == 0
317310
changed_when: false
318311
failed_when: false
319312
when:
320313
- terrarium_idp_mode == 'local'
321314
- terrarium_auth_domain | default('') | length > 0
322315

323-
- name: Restart Traefik to retry local auth ACME after public TLS wait failure
316+
- name: Restart Traefik to retry local auth TLS after trusted TLS wait failure
324317
ansible.builtin.systemd:
325318
name: traefik
326319
state: restarted
327320
when:
328321
- terrarium_idp_mode == 'local'
329322
- terrarium_auth_domain | default('') | length > 0
330-
- terrarium_auth_public_tls is defined
331-
- terrarium_auth_public_tls.rc | default(0) != 0
323+
- terrarium_auth_trusted_tls is defined
324+
- terrarium_auth_trusted_tls.rc | default(0) != 0
332325

333-
- name: Wait again for local auth domain to serve public TLS after ACME retry
326+
- name: Wait again for local auth domain to serve trusted TLS after retry
334327
ansible.builtin.command:
335328
argv:
336329
- curl
@@ -344,19 +337,40 @@
344337
- --max-time
345338
- "20"
346339
- "https://{{ terrarium_auth_domain }}/.well-known/openid-configuration"
347-
register: terrarium_auth_public_tls_retry
340+
register: terrarium_auth_trusted_tls_retry
348341
retries: 36
349342
delay: 10
350-
until: terrarium_auth_public_tls_retry.rc == 0
343+
until: terrarium_auth_trusted_tls_retry.rc == 0
344+
changed_when: false
345+
failed_when: false
346+
when:
347+
- terrarium_idp_mode == 'local'
348+
- terrarium_auth_domain | default('') | length > 0
349+
- terrarium_auth_trusted_tls is defined
350+
- terrarium_auth_trusted_tls.rc | default(0) != 0
351+
352+
- name: Verify local auth domain serves trusted TLS after waits
353+
ansible.builtin.command:
354+
argv:
355+
- curl
356+
- -fsS
357+
- --noproxy
358+
- "*"
359+
- --resolve
360+
- "{{ terrarium_auth_domain }}:443:127.0.0.1"
361+
- --connect-timeout
362+
- "10"
363+
- --max-time
364+
- "20"
365+
- "https://{{ terrarium_auth_domain }}/.well-known/openid-configuration"
366+
register: terrarium_auth_trusted_tls_final
351367
changed_when: false
352368
failed_when: false
353369
when:
354370
- terrarium_idp_mode == 'local'
355371
- terrarium_auth_domain | default('') | length > 0
356-
- terrarium_auth_public_tls is defined
357-
- terrarium_auth_public_tls.rc | default(0) != 0
358372

359-
- name: Show local auth TLS diagnostics after ACME retry failure
373+
- name: Show local auth TLS diagnostics after trusted TLS failure
360374
ansible.builtin.shell: |
361375
set +e
362376
echo "== presented certificate =="
@@ -372,17 +386,17 @@
372386
when:
373387
- terrarium_idp_mode == 'local'
374388
- terrarium_auth_domain | default('') | length > 0
375-
- terrarium_auth_public_tls_retry is defined
376-
- terrarium_auth_public_tls_retry.rc | default(0) != 0
389+
- terrarium_auth_trusted_tls_final is defined
390+
- terrarium_auth_trusted_tls_final.rc | default(0) != 0
377391

378-
- name: Fail when local auth domain still does not serve public TLS
392+
- name: Fail when local auth domain still does not serve trusted TLS
379393
ansible.builtin.fail:
380-
msg: "Local auth domain {{ terrarium_auth_domain }} still does not serve public TLS after retiring bootstrap TLS; see Traefik ACME diagnostics above."
394+
msg: "Local auth domain {{ terrarium_auth_domain }} still does not serve TLS trusted by the host; see Traefik TLS diagnostics above."
381395
when:
382396
- terrarium_idp_mode == 'local'
383397
- terrarium_auth_domain | default('') | length > 0
384-
- terrarium_auth_public_tls_retry is defined
385-
- terrarium_auth_public_tls_retry.rc | default(0) != 0
398+
- terrarium_auth_trusted_tls_final is defined
399+
- terrarium_auth_trusted_tls_final.rc | default(0) != 0
386400

387401
- name: Enable Traefik sync timer after dependent services are configured
388402
ansible.builtin.systemd:

tests/ansible-bootstrap-cert.test.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,22 @@ describe("Traefik bootstrap certificate template", () => {
4949
expect(tasks).toContain("Remove Traefik bootstrap certificate config when bootstrap TLS is not required");
5050
expect(tasks).toContain("Remove temporary Traefik bootstrap routes when bootstrap TLS is not required");
5151
expect(tasks).toContain("systemctl try-restart snap.lxd.daemon.service");
52-
expect(playbook).toContain("Remove local auth bootstrap TLS material before requesting public TLS");
52+
expect(playbook).toContain("Remove local auth bootstrap routes before requesting public TLS");
5353
expect(playbook).toContain("dynamic/bootstrap-routes.yml");
54-
expect(playbook).toContain("Wait for local auth domain to serve public TLS");
55-
expect(playbook).toContain("Restart Traefik to retry local auth ACME after public TLS wait failure");
56-
expect(playbook).toContain("Wait again for local auth domain to serve public TLS after ACME retry");
57-
expect(playbook).toContain("Show local auth TLS diagnostics after ACME retry failure");
58-
expect(playbook).toContain("Fail when local auth domain still does not serve public TLS");
54+
expect(playbook).not.toContain('"{{ terrarium_traefik_config_dir }}/dynamic/bootstrap-cert.yml"');
55+
expect(playbook).not.toContain('"{{ terrarium_traefik_config_dir }}/bootstrap-certs"');
56+
expect(playbook).not.toContain("/usr/local/share/ca-certificates/terrarium-bootstrap.crt");
57+
expect(playbook).toContain("Wait for local auth domain to serve trusted TLS");
58+
expect(playbook).toContain("Restart Traefik to retry local auth TLS after trusted TLS wait failure");
59+
expect(playbook).toContain("Wait again for local auth domain to serve trusted TLS after retry");
60+
expect(playbook).toContain("Verify local auth domain serves trusted TLS after waits");
61+
expect(playbook).toContain("Show local auth TLS diagnostics after trusted TLS failure");
62+
expect(playbook).toContain("Fail when local auth domain still does not serve trusted TLS");
63+
expect(playbook).toContain("terrarium_auth_trusted_tls_final.rc");
5964
expect(playbook).toContain("journalctl -u traefik");
60-
expect(playbook).toContain("terrarium_bootstrap_tls_removed is changed");
61-
expect(playbook.indexOf("Remove local auth bootstrap TLS material before requesting public TLS")).toBeLessThan(
62-
playbook.indexOf("Wait for local auth domain to serve public TLS")
65+
expect(playbook).toContain("terrarium_bootstrap_routes_removed is changed");
66+
expect(playbook.indexOf("Remove local auth bootstrap routes before requesting public TLS")).toBeLessThan(
67+
playbook.indexOf("Wait for local auth domain to serve trusted TLS")
6368
);
6469
});
6570

tests/integration/assertions/browser.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
isLoginOrOauthCallbackPlumbingPath,
1212
isTargetApplicationPage,
1313
isTargetLoginOrOauthPlumbingPage,
14-
lxdOidcLoginUrlForSsoPage
14+
lxdOidcLoginUrlForSsoPage,
15+
shouldIgnoreHttpsErrors
1516
} from "./browser";
1617

1718
describe("browser assertion helpers", () => {
@@ -79,6 +80,13 @@ describe("browser assertion helpers", () => {
7980
expect(new Set([allowPath, denyPath, denyFailurePath]).size).toBe(3);
8081
});
8182

83+
test("ignores HTTPS errors for host-pinned browser flows unless explicitly disabled", () => {
84+
expect(shouldIgnoreHttpsErrors({ resolveHosts: { "app.example.test": "203.0.113.10" } })).toBe(true);
85+
expect(shouldIgnoreHttpsErrors({ resolveHosts: { "app.example.test": "203.0.113.10" }, ignoreHTTPSErrors: false })).toBe(false);
86+
expect(shouldIgnoreHttpsErrors({ ignoreHTTPSErrors: true })).toBe(true);
87+
expect(shouldIgnoreHttpsErrors({})).toBe(false);
88+
});
89+
8290
test("formats denied-route target failures with final URL and body snippet", () => {
8391
const message = formatDeniedTargetRouteFailure("https://app.example.test/protected", "terrarium-proxy-ok\nfixture reached");
8492

@@ -112,6 +120,18 @@ describe("browser assertion helpers", () => {
112120
)
113121
).toBe(false);
114122

123+
expect(
124+
isRetryableBlankNavigationError(
125+
new Error(
126+
[
127+
"none of the identity selectors were visible: input[name=\"loginName\"]",
128+
"current URL: https://issuer.example.test/ui/v2/login/loginname?requestId=oidc_123",
129+
"body:\n<empty>"
130+
].join("\n")
131+
)
132+
)
133+
).toBe(true);
134+
115135
expect(
116136
isRetryableBlankNavigationError(
117137
new Error(

0 commit comments

Comments
 (0)