gowalk-cicd 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.8
|
|
@@ -118,6 +118,7 @@ def enabled_capabilities(token: str, bundle_pk: str) -> set[str]:
|
|
|
118
118
|
capability = (item.get("attributes") or {}).get("capabilityType")
|
|
119
119
|
if capability:
|
|
120
120
|
found.add(capability)
|
|
121
|
+
print(f"App ID {bundle_pk} capabilities: {', '.join(sorted(found)) or '(none)'}")
|
|
121
122
|
return found
|
|
122
123
|
|
|
123
124
|
|
|
@@ -132,7 +133,6 @@ def enable_capability(token: str, bundle_pk: str, capability: str) -> bool:
|
|
|
132
133
|
}
|
|
133
134
|
}
|
|
134
135
|
try:
|
|
135
|
-
# 409 means another writer got there first — the desired end state.
|
|
136
136
|
response = request(
|
|
137
137
|
"POST", "/bundleIdCapabilities", token,
|
|
138
138
|
json_body=body, allow_status={200, 201, 409},
|
|
@@ -141,6 +141,14 @@ def enable_capability(token: str, bundle_pk: str, capability: str) -> bool:
|
|
|
141
141
|
print(f"::warning::could not enable {capability}: {exc!r}")
|
|
142
142
|
return False
|
|
143
143
|
if response.status_code == 409:
|
|
144
|
+
# Could be "already on" — or Apple refusing outright, which reads
|
|
145
|
+
# identically from the status code alone. Surface the body: without it
|
|
146
|
+
# the run just reports a profile missing a capability we claimed to
|
|
147
|
+
# have enabled, and there is nothing in the log to explain why.
|
|
148
|
+
print(
|
|
149
|
+
f"::warning::App Store Connect returned 409 for {capability}: "
|
|
150
|
+
f"{response.text[:600]}"
|
|
151
|
+
)
|
|
144
152
|
return False
|
|
145
153
|
print(f"Enabled {capability} on the App ID")
|
|
146
154
|
return True
|
|
@@ -149,9 +157,13 @@ def enable_capability(token: str, bundle_pk: str, capability: str) -> bool:
|
|
|
149
157
|
def reconcile(token: str, bundle_pk: str, bundle_id: str, entitlement_keys: set[str]) -> bool:
|
|
150
158
|
"""Enable every simple capability the entitlements imply.
|
|
151
159
|
|
|
152
|
-
Returns True when
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
Returns True when the caller must regenerate the profile — which is
|
|
161
|
+
whenever the App ID was missing something, NOT merely when a POST
|
|
162
|
+
succeeded. A cached profile was issued while the App ID lacked these, so
|
|
163
|
+
reusing it reproduces the same archive failure either way; regenerating at
|
|
164
|
+
least picks up the App ID's current state, and if the capability is still
|
|
165
|
+
absent the error comes from Apple describing the real problem rather than
|
|
166
|
+
from a stale cache.
|
|
155
167
|
"""
|
|
156
168
|
warn_about_manual_entitlements(entitlement_keys, bundle_id)
|
|
157
169
|
wanted = required_capabilities(entitlement_keys)
|
|
@@ -164,9 +176,6 @@ def reconcile(token: str, bundle_pk: str, bundle_id: str, entitlement_keys: set[
|
|
|
164
176
|
f"{bundle_id}: entitlements require {', '.join(sorted(missing))} "
|
|
165
177
|
f"but the App ID does not have them; enabling"
|
|
166
178
|
)
|
|
167
|
-
|
|
168
|
-
# must be attempted, not just up to the first success.
|
|
169
|
-
return any([
|
|
179
|
+
for capability in sorted(missing):
|
|
170
180
|
enable_capability(token, bundle_pk, capability)
|
|
171
|
-
|
|
172
|
-
])
|
|
181
|
+
return True
|
|
@@ -109,15 +109,36 @@ class ReconcileTest(unittest.TestCase):
|
|
|
109
109
|
|
|
110
110
|
self.assertEqual(sorted(posted), ["APP_ATTEST", "PUSH_NOTIFICATIONS"])
|
|
111
111
|
|
|
112
|
-
def
|
|
112
|
+
def test_regenerates_even_when_the_capability_could_not_be_enabled(self) -> None:
|
|
113
|
+
# A 409 (or any refusal) still means the cached profile was issued
|
|
114
|
+
# while the App ID lacked the capability. Reusing it reproduces the
|
|
115
|
+
# archive failure and hides Apple's real error behind a stale cache.
|
|
116
|
+
response = self._response(409)
|
|
117
|
+
response.text = '{"errors":[{"detail":"nope"}]}'
|
|
113
118
|
with mock.patch.object(capabilities, "get_json", return_value={"data": []}), \
|
|
114
|
-
mock.patch.object(capabilities, "request", return_value=
|
|
119
|
+
mock.patch.object(capabilities, "request", return_value=response):
|
|
115
120
|
changed = capabilities.reconcile(
|
|
116
121
|
"tok", "PK", "com.gowalk.form",
|
|
117
122
|
{"com.apple.developer.devicecheck.appattest-environment"},
|
|
118
123
|
)
|
|
119
124
|
|
|
120
|
-
self.
|
|
125
|
+
self.assertTrue(changed)
|
|
126
|
+
|
|
127
|
+
def test_surfaces_the_409_body(self) -> None:
|
|
128
|
+
response = self._response(409)
|
|
129
|
+
response.text = '{"errors":[{"detail":"capability is not modifiable"}]}'
|
|
130
|
+
with mock.patch.object(capabilities, "get_json", return_value={"data": []}), \
|
|
131
|
+
mock.patch.object(capabilities, "request", return_value=response), \
|
|
132
|
+
mock.patch("builtins.print") as printed:
|
|
133
|
+
capabilities.reconcile(
|
|
134
|
+
"tok", "PK", "com.gowalk.form",
|
|
135
|
+
{"com.apple.developer.devicecheck.appattest-environment"},
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
messages = [c.args[0] for c in printed.call_args_list if c.args]
|
|
139
|
+
self.assertTrue(
|
|
140
|
+
any("capability is not modifiable" in m for m in messages), messages
|
|
141
|
+
)
|
|
121
142
|
|
|
122
143
|
def test_api_failure_does_not_raise(self) -> None:
|
|
123
144
|
with mock.patch.object(capabilities, "get_json", return_value={"data": []}), \
|
|
@@ -127,11 +148,13 @@ class ReconcileTest(unittest.TestCase):
|
|
|
127
148
|
{"com.apple.developer.devicecheck.appattest-environment"},
|
|
128
149
|
)
|
|
129
150
|
|
|
130
|
-
self.
|
|
151
|
+
self.assertTrue(changed)
|
|
131
152
|
|
|
132
153
|
def test_systemexit_from_asc_does_not_kill_signing(self) -> None:
|
|
133
154
|
# asc_common.request raises SystemExit, not Exception, so a bare
|
|
134
155
|
# `except Exception` would let an Apple 4xx abort the whole run.
|
|
156
|
+
# An unreadable App ID is also unknown state, so the profile is
|
|
157
|
+
# regenerated rather than trusted from cache.
|
|
135
158
|
with mock.patch.object(capabilities, "get_json", side_effect=SystemExit("400")), \
|
|
136
159
|
mock.patch.object(capabilities, "request", side_effect=SystemExit("400")):
|
|
137
160
|
changed = capabilities.reconcile(
|
|
@@ -139,7 +162,7 @@ class ReconcileTest(unittest.TestCase):
|
|
|
139
162
|
{"com.apple.developer.devicecheck.appattest-environment"},
|
|
140
163
|
)
|
|
141
164
|
|
|
142
|
-
self.
|
|
165
|
+
self.assertTrue(changed)
|
|
143
166
|
|
|
144
167
|
def test_capability_listing_sends_no_limit_parameter(self) -> None:
|
|
145
168
|
# /bundleIds/{id}/bundleIdCapabilities rejects `limit` with
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.8
|