mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
fix(ci): resolve test-development, nextcloud, and container CA failures
- plugins/lookup/config.py: honor default by setting skip_missing_app=not strict
so lookup('config', app, path, default) returns the default when the app is
missing from the applications dict, instead of raising during early constructor
phases. Fixes 5 test-development jobs.
- roles/web-app-nextcloud/files/playwright.spec.js: replace unsupported
.toSatisfy() with a boolean check inside expect.poll() + .toBe(true).
Fixes Deploy web-app-nextcloud.
- roles/sys-svc-container/files/container.py: when the target image has no
ENTRYPOINT, inject the internal CA as a volume plus NODE_EXTRA_CA_CERTS,
SSL_CERT_FILE, REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE instead of falling
back to a plain 'docker run' without CA trust. Fixes npm
UNABLE_TO_VERIFY_LEAF_SIGNATURE inside Microsoft Playwright images for
moodle, prometheus and onlyoffice deploys.
- tests/unit/roles/sys-svc-container/files/test_container.py: cover the new
no-ENTRYPOINT CA-injection path.
Note: web-app-mini-qr 'lookup ghcr.io: no such host' is not addressed here
and likely needs a separate investigation of CoreDNS forwarding on the CI
runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f5d79f111
commit
f1ea036bd2
4 files changed
+84
-8
No files matched your search
@@ -53,7 +53,7 @@ class LookupModule(LookupBase):
|
||||
config_path=config_path,
|
||||
strict=strict,
|
||||
default=default_value,
|
||||
skip_missing_app=False,
|
||||
skip_missing_app=not strict,
|
||||
)
|
||||
|
||||
# lookup plugins must return a list
|
||||
|
||||
@@ -367,9 +367,31 @@ def container_run(argv: List[str], debug: bool, with_ca: bool) -> int:
|
||||
if not ep:
|
||||
warn(
|
||||
"Image has no ENTRYPOINT and none was provided. "
|
||||
"Running without CA wrapper."
|
||||
"Injecting CA env vars without entrypoint wrapper."
|
||||
)
|
||||
# Inject CA cert as a volume + env vars so Node.js (NODE_EXTRA_CA_CERTS),
|
||||
# curl (CURL_CA_BUNDLE), Python requests (REQUESTS_CA_BUNDLE), and other
|
||||
# tools can trust the internal CA even without a wrapper entrypoint.
|
||||
ca_inject_opts: List[str] = [
|
||||
"-v",
|
||||
f"{ca_host}:{ca_container}:ro",
|
||||
"-e",
|
||||
f"CA_TRUST_CERT={ca_container}",
|
||||
"-e",
|
||||
f"CA_TRUST_NAME={trust_name}",
|
||||
"-e",
|
||||
f"NODE_EXTRA_CA_CERTS={ca_container}",
|
||||
"-e",
|
||||
f"SSL_CERT_FILE={ca_container}",
|
||||
"-e",
|
||||
f"REQUESTS_CA_BUNDLE={ca_container}",
|
||||
"-e",
|
||||
f"CURL_CA_BUNDLE={ca_container}",
|
||||
]
|
||||
return exec_docker(
|
||||
["docker", "run"] + run_opts + ca_inject_opts + [image] + user_args,
|
||||
debug=debug,
|
||||
)
|
||||
return exec_docker(["docker", "run", *argv], debug=debug)
|
||||
|
||||
final_cmd.extend(ep)
|
||||
final_cmd.extend(user_args)
|
||||
|
||||
@@ -419,17 +419,15 @@ test("dashboard to nextcloud login", async ({ page }) => {
|
||||
async () => {
|
||||
const iframeHandle = await nextcloudIframe.elementHandle();
|
||||
const iframeFrame = iframeHandle ? await iframeHandle.contentFrame() : null;
|
||||
|
||||
return iframeFrame ? iframeFrame.url() : "";
|
||||
const currentUrl = iframeFrame ? iframeFrame.url() : "";
|
||||
return currentUrl.includes(expectedOidcAuthUrl) || currentUrl.startsWith(expectedNextcloudBaseUrl);
|
||||
},
|
||||
{
|
||||
timeout: 60_000,
|
||||
message: `Expected Nextcloud iframe to load either the Keycloak OIDC login or the standalone Nextcloud login page`
|
||||
}
|
||||
)
|
||||
.toSatisfy((currentUrl) => {
|
||||
return currentUrl.includes(expectedOidcAuthUrl) || currentUrl.startsWith(expectedNextcloudBaseUrl);
|
||||
});
|
||||
.toBe(true);
|
||||
|
||||
await enterNextcloudLoginThroughVisibleEntryPoint(
|
||||
page,
|
||||
|
||||
@@ -324,6 +324,62 @@ class TestContainerWrapper(unittest.TestCase):
|
||||
os.environ.clear()
|
||||
os.environ.update(old_env)
|
||||
|
||||
def test_container_run_injects_ca_env_when_image_has_no_entrypoint(self):
|
||||
"""
|
||||
When with_ca=True, CA env is available, but the image has no ENTRYPOINT,
|
||||
container_run() must inject CA env vars and volume without an entrypoint wrapper.
|
||||
"""
|
||||
old_env = dict(os.environ)
|
||||
calls = []
|
||||
|
||||
def fake_exec_docker(cmd, debug=False):
|
||||
calls.append(("exec_docker", cmd, debug))
|
||||
return 0
|
||||
|
||||
def fake_try_inspect_no_ep(image, pull_policy):
|
||||
return [] # no entrypoint
|
||||
|
||||
orig_exec_docker = container.exec_docker
|
||||
orig_try_inspect = container.try_inspect_entrypoint_with_pull
|
||||
try:
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
td_path = Path(td)
|
||||
ca_file = td_path / "root-ca.crt"
|
||||
wrapper_file = td_path / "with-ca-trust.sh"
|
||||
ca_file.write_text("dummy-ca\n", encoding="utf-8")
|
||||
wrapper_file.write_text("#!/bin/sh\necho ok\n", encoding="utf-8")
|
||||
|
||||
os.environ["CA_TRUST_CERT_HOST"] = str(ca_file)
|
||||
os.environ["CA_TRUST_WRAPPER_HOST"] = str(wrapper_file)
|
||||
os.environ["CA_TRUST_NAME"] = "test-ca"
|
||||
|
||||
container.exec_docker = fake_exec_docker
|
||||
container.try_inspect_entrypoint_with_pull = fake_try_inspect_no_ep
|
||||
|
||||
argv = ["--rm", "playwright:v1.0", "/bin/bash", "-lc", "npm install"]
|
||||
rc = container.container_run(argv, debug=False, with_ca=True)
|
||||
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(len(calls), 1)
|
||||
cmd = calls[0][1]
|
||||
# Must be a docker run command
|
||||
self.assertEqual(cmd[0], "docker")
|
||||
self.assertEqual(cmd[1], "run")
|
||||
# Must contain NODE_EXTRA_CA_CERTS injection
|
||||
cmd_str = " ".join(cmd)
|
||||
self.assertIn("NODE_EXTRA_CA_CERTS", cmd_str)
|
||||
self.assertIn("/tmp/infinito/ca/root-ca.crt", cmd_str)
|
||||
# Must NOT use --entrypoint (no wrapper)
|
||||
self.assertNotIn("--entrypoint", cmd_str)
|
||||
# Image and original command must appear
|
||||
self.assertIn("playwright:v1.0", cmd_str)
|
||||
self.assertIn("npm install", cmd_str)
|
||||
finally:
|
||||
container.exec_docker = orig_exec_docker
|
||||
container.try_inspect_entrypoint_with_pull = orig_try_inspect
|
||||
os.environ.clear()
|
||||
os.environ.update(old_env)
|
||||
|
||||
def test_container_run_with_ca_false_always_plain_docker_run(self):
|
||||
"""
|
||||
When with_ca=False, container_run() must always call plain container run (no env needed).
|
||||
|
||||
Reference in new issue
Block a user