From a55c0dda3308ebc56c977eff6b844e4cd431242b Mon Sep 17 00:00:00 2001
From: Tristan Simas
Date: Mon, 27 Jul 2026 21:33:45 -0400
Subject: [PATCH 1/2] Align local MCP onboarding with ChatGPT desktop
---
docs/source/user_guide/mcp_clients.rst | 43 ++++++++++---------
openhcs/mcp/client_registration.py | 13 +++---
packaging/installers/README.md | 33 +++++++-------
.../installers/macos/OpenHCSInstaller.swift | 6 +--
.../installers/windows/Install-OpenHCS.ps1 | 10 +++--
.../installer/test_macos_simple_installer.py | 5 +--
.../test_windows_simple_installer.py | 7 +--
.../agent/test_mcp_client_registration.py | 5 ++-
tests/unit/test_build_website.py | 6 +--
website/index.html | 12 +++---
10 files changed, 72 insertions(+), 68 deletions(-)
diff --git a/docs/source/user_guide/mcp_clients.rst b/docs/source/user_guide/mcp_clients.rst
index 05ae6e6ee..ed1968a57 100644
--- a/docs/source/user_guide/mcp_clients.rst
+++ b/docs/source/user_guide/mcp_clients.rst
@@ -10,12 +10,12 @@ Local installation
------------------
For normal desktop onboarding, download the native OpenHCS installer for
-Windows or macOS and leave **Connect OpenHCS to Codex and installed local AI
+Windows or macOS and leave **Connect OpenHCS to ChatGPT, Codex, and local AI
agent apps** checked. Setup installs the GUI and MCP runtime together, publishes
-one update-stable launcher, and registers that launcher with Codex plus other
-detected supported local clients. Restart the client after setup, accept its
-normal first-use trust prompt if shown, and ask it to use OpenHCS. This local
-Codex setup does not use ChatGPT Developer Mode.
+one update-stable launcher, and registers that launcher with ChatGPT desktop,
+Codex, and other detected supported local clients. Restart the clients after
+setup, accept their normal first-use trust prompt if shown, and ask them to use
+OpenHCS. This local desktop setup does not use ChatGPT Developer Mode.
The installer preserves unrelated MCP servers and replaces only the local entry
named ``openhcs``. Re-running Setup updates the private OpenHCS environment
@@ -137,12 +137,13 @@ Codex CLI fallback is a single local-server registration command:
--env OPENHCS_AGENT_WRITE_ROOTS=/path/to/openhcs-outputs \
-- uvx --from 'openhcs[gui,mcp]' openhcs-mcp
-The Codex app, CLI, and IDE extension share the MCP configuration for the same
-host. In the current unified ChatGPT desktop app, choose the distinct Codex
-view; that view retains the local Codex workflow and configuration. Restart the
-client after adding or installing the server. Chat and Work do not read this
-local configuration or directly start a local stdio MCP server; use a remote
-HTTPS app or Secure MCP Tunnel for those views as described below.
+ChatGPT desktop, the Codex app and CLI, and the Codex IDE extension share the
+MCP configuration for the same host. Restart ChatGPT desktop or Codex after
+adding or installing the server. In ChatGPT desktop, open **Settings**, then
+**MCP servers**, to inspect the connection; after restarting, ``/mcp`` shows
+the connected servers. The ChatGPT web client does not read this local
+configuration or directly start a local stdio MCP server; use a remote HTTPS
+app or Secure MCP Tunnel there as described below.
The native installer performs this local registration automatically. The CLI
command above remains the manual/package-manager fallback and is not required
@@ -197,19 +198,19 @@ local bridge.
Browser clients
---------------
-ChatGPT Chat and Work cannot directly install Python packages, launch
+The ChatGPT web client cannot directly install Python packages, launch
``openhcs-mcp`` over stdio, or start the native OpenHCS UI on the user's
-computer. Those views connect to remote MCP servers. A separately deployed
-HTTPS MCP service can operate on server-side workspaces; an OpenAI Secure MCP
-Tunnel can bridge an eligible ChatGPT workspace to a private deployment without
-exposing it publicly. Neither route is created merely by writing Codex's local
-configuration. The Codex view in the unified desktop app remains the local
-stdio route described above.
+computer. It connects to remote MCP servers. A separately deployed HTTPS MCP
+service can operate on server-side workspaces; an OpenAI Secure MCP Tunnel can
+bridge an eligible ChatGPT workspace to a private deployment without exposing
+it publicly. Neither route is created merely by writing the shared local
+ChatGPT desktop and Codex configuration. ChatGPT desktop remains a supported
+local stdio route as described above.
The hosted service exposes a smaller, read-only discovery surface rather than
your local OpenHCS installation. It requires OAuth and an isolated server-side
-workspace. Add the administrator-provided HTTPS MCP URL to ChatGPT, or follow
-the workspace administrator's Secure MCP Tunnel procedure. ChatGPT plan,
+workspace. Add the administrator-provided HTTPS MCP URL to ChatGPT web, or
+follow the workspace administrator's Secure MCP Tunnel procedure. ChatGPT plan,
workspace, Developer Mode, and approval requirements are controlled by OpenAI
-and may differ from local Codex onboarding. Do not expose ``openhcs-mcp`` or
+and may differ from local desktop onboarding. Do not expose ``openhcs-mcp`` or
``openhcs-mcp-http`` directly from a personal machine.
diff --git a/openhcs/mcp/client_registration.py b/openhcs/mcp/client_registration.py
index 4f51e9742..6bf800dee 100644
--- a/openhcs/mcp/client_registration.py
+++ b/openhcs/mcp/client_registration.py
@@ -269,15 +269,15 @@ def diagnostic_config_path(
class CodexClientRegistrationTarget(McpClientRegistrationTarget):
- """Codex app, CLI, and IDE shared TOML configuration."""
+ """ChatGPT desktop and Codex shared TOML configuration."""
target_id = "codex"
- display_name = "OpenAI Codex"
+ display_name = "ChatGPT desktop and OpenAI Codex"
executable_candidates = ("codex",)
@classmethod
def config_path(cls, environment: ClientRegistrationEnvironment) -> Path:
- """Return the shared Codex configuration path."""
+ """Return the shared ChatGPT desktop and Codex configuration path."""
configured_home = environment.environ.get("CODEX_HOME")
codex_home = (
Path(configured_home).expanduser()
@@ -637,7 +637,7 @@ def _update_codex_toml(
status=ClientRegistrationStatus.UNCHANGED,
config_path=os.fspath(path),
backup_path=None,
- message="OpenHCS is already registered with Codex.",
+ message="OpenHCS is already registered with ChatGPT desktop and Codex.",
)
server = (
@@ -658,7 +658,10 @@ def _update_codex_toml(
),
config_path=os.fspath(path),
backup_path=backup_path,
- message="Registered OpenHCS in the shared Codex MCP configuration.",
+ message=(
+ "Registered OpenHCS in the shared ChatGPT desktop and Codex "
+ "MCP configuration."
+ ),
)
diff --git a/packaging/installers/README.md b/packaging/installers/README.md
index 3b4b87e4a..fc4359738 100644
--- a/packaging/installers/README.md
+++ b/packaging/installers/README.md
@@ -49,9 +49,9 @@ and macOS users open one disk image. Installation stays inside a small native
window:
- Windows presents Welcome, installation-folder, progress, and Finish pages.
- Its checked agent option connects the Codex app/CLI/IDE and detected supported
- local clients. The final page reports whether those connections succeeded
- and can launch OpenHCS immediately.
+ Its checked agent option connects ChatGPT desktop, Codex app/CLI/IDE, and
+ detected supported local clients. The final page reports whether those
+ connections succeeded and can launch OpenHCS immediately.
- macOS presents Welcome, progress, and Finish pages in
``OpenHCS Installer.app``. Its equivalent checked agent option is shown on the
Welcome page, and the final page can launch OpenHCS immediately.
@@ -61,20 +61,19 @@ individual OpenHCS dependencies. Advanced output remains available through the
durable installer log when troubleshooting is needed.
After a successful agent connection, restart the local client and ask it to use
-OpenHCS. The Codex app, Codex CLI, and the Codex IDE extension share one
-registration. In the current unified ChatGPT desktop app, this is the distinct
-Codex view; select Codex before asking it to use OpenHCS. Claude Desktop,
-Cursor, Gemini CLI, and Windsurf are configured when detected; VS Code is
-registered through its supported command-line interface when available. A
-client may still show its normal first-use trust or tool-approval prompt. This
-local Codex setup does not use ChatGPT Developer Mode.
-
-The Chat and Work views in ChatGPT do not directly start this local stdio
-process or read Codex's local configuration. Those views require a remote HTTPS
-MCP app or an OpenAI Secure MCP Tunnel, with availability and approval
-controlled by the user's ChatGPT plan and workspace. The official MCP Registry
-record provides distribution discovery and verification, not a
-browser-to-local bridge.
+OpenHCS. ChatGPT desktop, the Codex app and CLI, and the Codex IDE extension
+share one registration. In ChatGPT desktop, use **Settings > MCP servers** to
+inspect the connection and ``/mcp`` after restarting to list connected servers.
+Claude Desktop, Cursor, Gemini CLI, and Windsurf are configured when detected;
+VS Code is registered through its supported command-line interface when
+available. A client may still show its normal first-use trust or tool-approval
+prompt. This local desktop setup does not use ChatGPT Developer Mode.
+
+The ChatGPT web client does not directly start this local stdio process or read
+the shared local configuration. It requires a remote HTTPS MCP app or an OpenAI
+Secure MCP Tunnel, with availability and approval controlled by the user's
+ChatGPT plan and workspace. The official MCP Registry record provides
+distribution discovery and verification, not a browser-to-local bridge.
## Source validation
diff --git a/packaging/installers/macos/OpenHCSInstaller.swift b/packaging/installers/macos/OpenHCSInstaller.swift
index a44590110..51c01e639 100644
--- a/packaging/installers/macos/OpenHCSInstaller.swift
+++ b/packaging/installers/macos/OpenHCSInstaller.swift
@@ -90,7 +90,7 @@ private final class InstallerController: NSObject, NSApplicationDelegate,
private let progressIndicator = NSProgressIndicator()
private let connectAgentsCheckbox = NSButton(
checkboxWithTitle:
- "Connect OpenHCS to Codex and installed local AI agent apps",
+ "Connect OpenHCS to ChatGPT, Codex, and local AI agent apps",
target: nil,
action: nil
)
@@ -345,10 +345,10 @@ private final class InstallerController: NSObject, NSApplicationDelegate,
if installerStateValue(named: "agent-registration-status") == "connected" {
let connectedClients =
installerStateValue(named: "agent-registration-summary")
- ?? "Codex and detected local agent apps"
+ ?? "ChatGPT desktop, Codex, and detected local agent apps"
detailLabel.stringValue =
"OpenHCS is connected to \(connectedClients). "
- + "In ChatGPT desktop, choose Codex. Restart other listed apps, "
+ + "Restart ChatGPT desktop, Codex, and other listed apps, "
+ "then ask them to use OpenHCS."
} else if installerStateValue(
named: "agent-registration-status"
diff --git a/packaging/installers/windows/Install-OpenHCS.ps1 b/packaging/installers/windows/Install-OpenHCS.ps1
index 003c393f7..5cec66bde 100644
--- a/packaging/installers/windows/Install-OpenHCS.ps1
+++ b/packaging/installers/windows/Install-OpenHCS.ps1
@@ -1059,7 +1059,7 @@ function Show-InstallerWindow {
$agentConnectionCheck = New-Object Windows.Forms.CheckBox
$agentConnectionCheck.Text = (
- "Connect OpenHCS to Codex and installed local AI agent apps"
+ "Connect OpenHCS to ChatGPT, Codex, and local AI agent apps"
)
$agentConnectionCheck.Checked = $true
$agentConnectionCheck.Location = New-Object Drawing.Point(31, 201)
@@ -1470,7 +1470,9 @@ function Show-InstallerWindow {
).Trim()
}
if ($registrationStatus -eq "connected") {
- $connectedClients = "Codex and detected local agent apps"
+ $connectedClients = (
+ "ChatGPT desktop, Codex, and detected local agent apps"
+ )
$registrationReportPath = [IO.Path]::Combine(
$script:ActiveInstallRoot, "agent-registration.json"
)
@@ -1498,8 +1500,8 @@ function Show-InstallerWindow {
}
$completionMessage = (
"$($Contract.ProductName) is connected to $connectedClients. " +
- "In ChatGPT desktop, choose Codex. Restart other listed " +
- "apps, then ask them to use OpenHCS."
+ "Restart ChatGPT desktop, Codex, and other listed apps, " +
+ "then ask them to use OpenHCS."
)
}
else {
diff --git a/tests/installer/test_macos_simple_installer.py b/tests/installer/test_macos_simple_installer.py
index f9f565c79..54a0ec34c 100644
--- a/tests/installer/test_macos_simple_installer.py
+++ b/tests/installer/test_macos_simple_installer.py
@@ -284,13 +284,12 @@ def test_macos_installer_registers_agent_clients_through_stable_launcher() -> No
assert '"$registration_ok" != true' in source
assert "connectAgentsCheckbox" in app_source
- assert "Connect OpenHCS to Codex and installed local AI agent apps" in app_source
- assert "ChatGPT/Codex" not in app_source
+ assert "Connect OpenHCS to ChatGPT, Codex, and local AI agent apps" in app_source
assert "connectAgentsCheckbox.state = .on" in app_source
assert 'environment["OPENHCS_INSTALLER_REGISTER_MCP_CLIENTS"]' in app_source
assert 'installerStateValue(named: "agent-registration-status")' in app_source
assert 'installerStateValue(named: "agent-registration-summary")' in app_source
- assert "In ChatGPT desktop, choose Codex" in app_source
+ assert "Restart ChatGPT desktop, Codex, and other listed apps" in app_source
macos_smoke = workflow[
workflow.index(
diff --git a/tests/installer/test_windows_simple_installer.py b/tests/installer/test_windows_simple_installer.py
index cdc6cb71b..834ebec80 100644
--- a/tests/installer/test_windows_simple_installer.py
+++ b/tests/installer/test_windows_simple_installer.py
@@ -257,10 +257,7 @@ def test_windows_wizard_owns_liveness_failure_and_optional_launch_ui() -> None:
assert '$openLogButton.Text = "Open log"' in source
assert '$launchCheck.Text = "Launch $($Contract.ProductName) after setup"' in source
assert "$launchCheck.Checked = $true" in source
- assert (
- '"Connect OpenHCS to Codex and installed local AI agent apps"' in source
- )
- assert "ChatGPT/Codex" not in source
+ assert '"Connect OpenHCS to ChatGPT, Codex, and local AI agent apps"' in source
assert "$agentConnectionCheck.Checked = $true" in source
assert "Get-DesktopShortcutPath $Contract" in source
assert "Start-Process -FilePath (Get-DesktopShortcutPath $Contract)" in source
@@ -295,7 +292,7 @@ def test_windows_installer_registers_agent_clients_through_stable_launcher() ->
assert "$registrationReport.results" in source
assert "[string]$_.display_name" in source
assert "Register-InstalledMcpClients" in source
- assert "In ChatGPT desktop, choose Codex" in source
+ assert "Restart ChatGPT desktop, Codex, and other listed apps" in source
assert "$exitCode -ne 0" in source
assert "$report.ok -ne $true" in source
assert source.index("Publish-LaunchAdapterAndShortcut `") < source.index(
diff --git a/tests/unit/agent/test_mcp_client_registration.py b/tests/unit/agent/test_mcp_client_registration.py
index 7fbc5a827..aeabd4b22 100644
--- a/tests/unit/agent/test_mcp_client_registration.py
+++ b/tests/unit/agent/test_mcp_client_registration.py
@@ -70,7 +70,10 @@ def test_registered_client_targets_are_the_client_semantic_authority() -> None:
"windsurf": WindsurfClientRegistrationTarget,
"vscode": VsCodeClientRegistrationTarget,
}
- assert CodexClientRegistrationTarget.display_name == "OpenAI Codex"
+ assert (
+ CodexClientRegistrationTarget.display_name
+ == "ChatGPT desktop and OpenAI Codex"
+ )
def test_codex_registration_preserves_unrelated_toml_and_creates_backup(
diff --git a/tests/unit/test_build_website.py b/tests/unit/test_build_website.py
index 502bed134..71e71de53 100644
--- a/tests/unit/test_build_website.py
+++ b/tests/unit/test_build_website.py
@@ -70,11 +70,11 @@ def test_shipping_copy_projects_current_release_and_keeps_boundaries_explicit(
assert f"OpenHCS {package_version} on PyPI" in html
assert f"Local MCP in OpenHCS {package_version}" in html
assert "one-click local agent" in html
- assert "Codex view in ChatGPT desktop" in html
+ assert "ChatGPT desktop app and Codex app/CLI/IDE" in html
assert "ChatGPT" in html
- assert "Chat and Work require a remote HTTPS" in html
+ assert "ChatGPT web requires a remote HTTPS" in html
assert "Secure MCP Tunnel" in html
- assert "ChatGPT desktop/Codex" not in html
+ assert "shared ChatGPT desktop/Codex configuration" in html
installer_assets = re.findall(
r"https://github\.com/OpenHCSDev/OpenHCS/releases/latest/download/" r"([^\"]+)",
html,
diff --git a/website/index.html b/website/index.html
index 8ce4a2d91..45368cc75 100644
--- a/website/index.html
+++ b/website/index.html
@@ -255,9 +255,9 @@ Give your agent the
same mental model.
The mcp extra and local stdio server ship with OpenHCS
{{ OPENHCS_VERSION }}. The desktop installer can connect the stable
local server to detected supported local clients, including the
- Codex view in ChatGPT desktop and Codex CLI/IDE; official registry
- metadata, Codex configuration, and Claude packaging come from the
- same release source.
+ ChatGPT desktop app and Codex app/CLI/IDE; official registry
+ metadata, shared ChatGPT desktop/Codex configuration, and Claude
+ packaging come from the same release source.
- 01 Function discovery and typed pipeline authoring over local stdio
@@ -339,9 +339,9 @@ Install your way.
User-scoped, CPU-only installation with CellProfiler compatibility, local MCP,
Napari, and Fiji/Bio-Formats support. Leave the agent option checked to connect
- Codex and detected supported local clients, then restart the client. In the
- unified ChatGPT desktop app, choose Codex; Chat and Work require a remote HTTPS
- app or an eligible Secure MCP Tunnel. GPU libraries are not included.
+ ChatGPT desktop, Codex, and detected supported local clients, then restart the
+ clients and ask them to use OpenHCS. ChatGPT web requires a remote HTTPS app or
+ an eligible Secure MCP Tunnel. GPU libraries are not included.
Fiji Java components are resolved on first use.
Initial assets are not code-signed, and the macOS app is not notarized, so your
OS may ask you to confirm trust.
From 19ca5cb620ee8c50285ee4916c4e9e7854294920 Mon Sep 17 00:00:00 2001
From: Tristan Simas
Date: Mon, 27 Jul 2026 21:40:06 -0400
Subject: [PATCH 2/2] Require accepted macOS notarization logs
---
docs/source/development/mcp_release.rst | 16 ++++++---
packaging/installers/macos/Sign-Installer.sh | 35 ++++++++++++++++++++
tests/installer/test_installer_signing.py | 13 ++++++++
3 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/docs/source/development/mcp_release.rst b/docs/source/development/mcp_release.rst
index 1d44ff17e..3fa3a14ad 100644
--- a/docs/source/development/mcp_release.rst
+++ b/docs/source/development/mcp_release.rst
@@ -200,8 +200,9 @@ The same helper can be invoked outside Actions after SimplySign is connected:
The macOS job requires a Developer ID Application certificate, not a Developer
ID Installer certificate, because the shipped objects are an application and
-disk image rather than a flat installer package. It also requires an App Store
-Connect API key authorized for the Apple notary service. Store:
+disk image rather than a flat installer package. It also requires a team App
+Store Connect API key authorized for the Apple notary service; Apple does not
+permit individual App Store Connect API keys to use ``notarytool``. Store:
.. code-block:: text
@@ -221,9 +222,12 @@ key; the key ID and issuer ID are the corresponding App Store Connect values.
The workflow imports the certificate into an ephemeral keychain, signs the app
with hardened runtime and a secure timestamp, verifies that signature, builds
and signs the DMG, and submits the exact DMG with ``notarytool --wait``. It
-requires the returned status to be ``Accepted``, staples and validates the
-ticket, and runs a Gatekeeper assessment before upload. Temporary keychains,
-certificate files, and API-key files are removed by the trust helper.
+requires the returned status to be ``Accepted``, retrieves the authoritative
+log for that exact submission with the same credentials, emits the complete
+log so Apple warnings remain visible, and independently requires the log status
+to be ``Accepted``. Only then does it staple and validate the ticket and run a
+Gatekeeper assessment before upload. Temporary keychains, certificate files,
+notarization logs, and API-key files are removed by the trust helper.
The DMG is the trust acceptance boundary because it is the exact outermost
file distributed to users. Apple directs custom distributions to sign nested
@@ -253,6 +257,8 @@ Publisher setup should follow the current primary platform guidance:
`_.
* `Apple custom notarization workflow
`_.
+* `Apple App Store Connect API key types
+ `_.
* `Apple packaging guidance for nested distributions
`_.
* `Apple Gatekeeper assessment with ``spctl``
diff --git a/packaging/installers/macos/Sign-Installer.sh b/packaging/installers/macos/Sign-Installer.sh
index c0ead99a1..8a398cfb9 100755
--- a/packaging/installers/macos/Sign-Installer.sh
+++ b/packaging/installers/macos/Sign-Installer.sh
@@ -164,6 +164,7 @@ sign_dmg_and_notarize() {
local notary_key_path="$temporary_directory/AuthKey.p8"
local notary_result_path="$temporary_directory/notary-result.json"
+ local notary_log_path="$temporary_directory/notary-log.json"
if ! printf '%s' "$OPENHCS_MACOS_NOTARY_KEY_BASE64" |
/usr/bin/base64 -D >"$notary_key_path"; then
printf '%s\n' \
@@ -195,6 +196,40 @@ sign_dmg_and_notarize() {
exit 1
fi
+ local notary_submission_id
+ notary_submission_id=$(
+ /usr/bin/plutil \
+ -extract id raw \
+ -o - \
+ "$notary_result_path"
+ )
+ if [[ -z "$notary_submission_id" ]]; then
+ printf 'Apple notarization returned no submission identifier.\n' >&2
+ exit 1
+ fi
+ if ! /usr/bin/xcrun notarytool log "$notary_submission_id" \
+ --key "$notary_key_path" \
+ --key-id "$OPENHCS_MACOS_NOTARY_KEY_ID" \
+ --issuer "$OPENHCS_MACOS_NOTARY_ISSUER_ID" \
+ "$notary_log_path"; then
+ printf 'Could not retrieve the Apple notarization log.\n' >&2
+ exit 1
+ fi
+ /bin/cat "$notary_log_path"
+
+ local notary_log_status
+ notary_log_status=$(
+ /usr/bin/plutil \
+ -extract status raw \
+ -o - \
+ "$notary_log_path"
+ )
+ if [[ "$notary_log_status" != Accepted ]]; then
+ printf 'Apple notarization log was not accepted: %s\n' \
+ "$notary_log_status" >&2
+ exit 1
+ fi
+
/usr/bin/xcrun stapler staple "$dmg_path"
/usr/bin/xcrun stapler validate "$dmg_path"
verify_timestamped_signature "$dmg_path"
diff --git a/tests/installer/test_installer_signing.py b/tests/installer/test_installer_signing.py
index 5f4695d12..09f5fc23b 100644
--- a/tests/installer/test_installer_signing.py
+++ b/tests/installer/test_installer_signing.py
@@ -118,6 +118,8 @@ def test_macos_release_uses_developer_id_notarytool_and_stapling() -> None:
verify = dmg.index('verify_timestamped_signature "$dmg_path"')
submit = dmg.index("/usr/bin/xcrun notarytool submit")
accepted = dmg.index('if [[ "$notary_status" != Accepted ]]')
+ log = dmg.index('/usr/bin/xcrun notarytool log "$notary_submission_id"')
+ log_accepted = dmg.index('if [[ "$notary_log_status" != Accepted ]]')
staple = dmg.index("/usr/bin/xcrun stapler staple")
validate = dmg.index("/usr/bin/xcrun stapler validate")
final_signature = dmg.rindex('verify_timestamped_signature "$dmg_path"')
@@ -128,6 +130,8 @@ def test_macos_release_uses_developer_id_notarytool_and_stapling() -> None:
< verify
< submit
< accepted
+ < log
+ < log_accepted
< staple
< validate
< final_signature
@@ -137,6 +141,15 @@ def test_macos_release_uses_developer_id_notarytool_and_stapling() -> None:
assert dmg.count('/usr/bin/hdiutil verify "$dmg_path"') == 2
assert "--wait" in dmg
assert "--output-format json" in dmg
+ assert "-extract id raw" in dmg
+ assert '"$notary_log_path"' in dmg
+ log_block = dmg[log:log_accepted]
+ for credential_argument in (
+ '--key "$notary_key_path"',
+ '--key-id "$OPENHCS_MACOS_NOTARY_KEY_ID"',
+ '--issuer "$OPENHCS_MACOS_NOTARY_ISSUER_ID"',
+ ):
+ assert credential_argument in log_block
def test_tag_workflow_cannot_upload_unsigned_native_artifacts() -> None: