gowalk-cicd 1.0.8 → 1.0.9

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/README.md CHANGED
@@ -206,15 +206,23 @@ Provisioning profile "CI-com.example.app" doesn't include the App Attest capabil
206
206
 
207
207
  Before creating a profile, the action reads the target's
208
208
  `CODE_SIGN_ENTITLEMENTS` plist and enables the matching capabilities on the App
209
- ID — Push Notifications, App Attest, Associated Domains, Sign in with Apple,
210
- HealthKit, SiriKit, NFC, HomeKit, network extensions and the other plain
211
- on/off toggles. If it had to turn anything on, it regenerates the profile
212
- rather than reusing the cached one, which predates the change.
213
-
214
- Capabilities that carry values an entitlements file cannot supply App Groups,
215
- iCloud containers, Apple Pay merchant IDs, Wallet pass types, Data Protection —
216
- are **not** enabled automatically. The action emits a `::warning::` naming what
217
- it saw and leaves those for you to configure in the Apple Developer portal.
209
+ ID — Push Notifications, Associated Domains, HealthKit, SiriKit, HomeKit,
210
+ network extensions and the other plain on/off toggles. Whenever the App ID was
211
+ missing something it regenerates the profile rather than reusing the cached
212
+ one, which was issued before the capability existed.
213
+
214
+ Two classes of capability are **not** enabled automatically, and each gets a
215
+ `::warning::` naming what was seen:
216
+
217
+ - **Values the action cannot infer** App Groups, iCloud containers, Apple Pay
218
+ merchant IDs, Wallet pass types, Data Protection. Configure these on the App
219
+ ID yourself.
220
+ - **App Attest** — a real App ID capability in the developer portal, but absent
221
+ from the ASC API's `capabilityType` enum, so *no* API call can turn it on.
222
+ Any app using Firebase App Check's `AppAttestProvider` must have App Attest
223
+ ticked once by hand under **Certificates, Identifiers & Profiles → Identifiers
224
+ → <your App ID>**. Until then the archive fails with `Provisioning profile
225
+ "CI-<bundle>" doesn't include the App Attest capability`.
218
226
 
219
227
  ## AI metadata auto-fill
220
228
 
@@ -1 +1 @@
1
- 1.0.8
1
+ 1.0.9
@@ -41,7 +41,6 @@ _API_FAILURES = (Exception, SystemExit)
41
41
  # capability at all.
42
42
  CAPABILITY_BY_ENTITLEMENT = {
43
43
  "aps-environment": "PUSH_NOTIFICATIONS",
44
- "com.apple.developer.devicecheck.appattest-environment": "APP_ATTEST",
45
44
  "com.apple.developer.associated-domains": "ASSOCIATED_DOMAINS",
46
45
  "com.apple.developer.applesignin": "APPLE_ID_AUTH",
47
46
  "com.apple.developer.networking.wifi-info": "ACCESS_WIFI_INFORMATION",
@@ -66,6 +65,14 @@ CAPABILITY_BY_ENTITLEMENT = {
66
65
  # unambiguously. Enabling these blind would create a half-configured App ID,
67
66
  # so we say what is missing and stop.
68
67
  MANUAL_ENTITLEMENTS = {
68
+ # App Attest is a real App ID capability in the developer portal, but it is
69
+ # absent from the ASC API's capabilityType enum entirely — POSTing it
70
+ # returns 409 ENTITY_ERROR.ATTRIBUTE.TYPE listing the valid values, which
71
+ # do not include it. There is no API to turn this one on.
72
+ "com.apple.developer.devicecheck.appattest-environment": (
73
+ "App Attest, which the App Store Connect API cannot enable — tick it "
74
+ "on the App ID under Certificates, Identifiers & Profiles"
75
+ ),
69
76
  "com.apple.security.application-groups": "App Groups",
70
77
  "com.apple.developer.icloud-container-identifiers": "iCloud",
71
78
  "com.apple.developer.icloud-services": "iCloud",
@@ -145,9 +152,12 @@ def enable_capability(token: str, bundle_pk: str, capability: str) -> bool:
145
152
  # identically from the status code alone. Surface the body: without it
146
153
  # the run just reports a profile missing a capability we claimed to
147
154
  # have enabled, and there is nothing in the log to explain why.
155
+ # Untruncated enough to show Apple's full list of valid capabilityType
156
+ # values, which is the only way to learn that a name is simply not
157
+ # API-manageable (see App Attest in MANUAL_ENTITLEMENTS).
148
158
  print(
149
159
  f"::warning::App Store Connect returned 409 for {capability}: "
150
- f"{response.text[:600]}"
160
+ f"{response.text[:2000]}"
151
161
  )
152
162
  return False
153
163
  print(f"Enabled {capability} on the App ID")
@@ -19,6 +19,7 @@ import capabilities
19
19
 
20
20
  ENTITLEMENTS = {
21
21
  "aps-environment": "production",
22
+ "com.apple.developer.associated-domains": ["applinks:gowalk.example"],
22
23
  "com.apple.developer.devicecheck.appattest-environment": "production",
23
24
  "keychain-access-groups": ["$(AppIdentifierPrefix)com.gowalk.form"],
24
25
  }
@@ -46,12 +47,26 @@ class ReadEntitlementsTest(unittest.TestCase):
46
47
 
47
48
  class RequiredCapabilitiesTest(unittest.TestCase):
48
49
  def test_maps_only_known_toggles(self) -> None:
49
- # keychain-access-groups needs no App ID capability at all.
50
+ # keychain-access-groups needs no App ID capability at all, and App
51
+ # Attest is not in the ASC API's capabilityType enum, so neither can
52
+ # produce a POST.
50
53
  self.assertEqual(
51
54
  capabilities.required_capabilities(set(ENTITLEMENTS)),
52
- {"PUSH_NOTIFICATIONS", "APP_ATTEST"},
55
+ {"PUSH_NOTIFICATIONS", "ASSOCIATED_DOMAINS"},
53
56
  )
54
57
 
58
+ def test_app_attest_is_reported_not_attempted(self) -> None:
59
+ key = "com.apple.developer.devicecheck.appattest-environment"
60
+
61
+ self.assertNotIn(key, capabilities.CAPABILITY_BY_ENTITLEMENT)
62
+ self.assertIn(key, capabilities.MANUAL_ENTITLEMENTS)
63
+
64
+ with mock.patch("builtins.print") as printed:
65
+ capabilities.warn_about_manual_entitlements({key}, "com.gowalk.form")
66
+
67
+ messages = [c.args[0] for c in printed.call_args_list if c.args]
68
+ self.assertTrue(any("App Attest" in m for m in messages), messages)
69
+
55
70
  def test_ignores_entitlements_with_no_capability(self) -> None:
56
71
  self.assertEqual(
57
72
  capabilities.required_capabilities({"get-task-allow", "com.apple.security.get-task-allow"}),
@@ -78,13 +93,13 @@ class ReconcileTest(unittest.TestCase):
78
93
  changed = capabilities.reconcile("tok", "PK", "com.gowalk.form", set(ENTITLEMENTS))
79
94
 
80
95
  self.assertTrue(changed)
81
- self.assertEqual(posted, ["APP_ATTEST"])
96
+ self.assertEqual(posted, ["ASSOCIATED_DOMAINS"])
82
97
 
83
98
  def test_no_op_when_the_app_id_already_has_everything(self) -> None:
84
99
  listed = {
85
100
  "data": [
86
101
  {"attributes": {"capabilityType": "PUSH_NOTIFICATIONS"}},
87
- {"attributes": {"capabilityType": "APP_ATTEST"}},
102
+ {"attributes": {"capabilityType": "ASSOCIATED_DOMAINS"}},
88
103
  ]
89
104
  }
90
105
  with mock.patch.object(capabilities, "get_json", return_value=listed), \
@@ -107,7 +122,7 @@ class ReconcileTest(unittest.TestCase):
107
122
  mock.patch.object(capabilities, "request", side_effect=fake_request):
108
123
  capabilities.reconcile("tok", "PK", "com.gowalk.form", set(ENTITLEMENTS))
109
124
 
110
- self.assertEqual(sorted(posted), ["APP_ATTEST", "PUSH_NOTIFICATIONS"])
125
+ self.assertEqual(sorted(posted), ["ASSOCIATED_DOMAINS", "PUSH_NOTIFICATIONS"])
111
126
 
112
127
  def test_regenerates_even_when_the_capability_could_not_be_enabled(self) -> None:
113
128
  # A 409 (or any refusal) still means the cached profile was issued
@@ -119,7 +134,7 @@ class ReconcileTest(unittest.TestCase):
119
134
  mock.patch.object(capabilities, "request", return_value=response):
120
135
  changed = capabilities.reconcile(
121
136
  "tok", "PK", "com.gowalk.form",
122
- {"com.apple.developer.devicecheck.appattest-environment"},
137
+ {"com.apple.developer.associated-domains"},
123
138
  )
124
139
 
125
140
  self.assertTrue(changed)
@@ -132,7 +147,7 @@ class ReconcileTest(unittest.TestCase):
132
147
  mock.patch("builtins.print") as printed:
133
148
  capabilities.reconcile(
134
149
  "tok", "PK", "com.gowalk.form",
135
- {"com.apple.developer.devicecheck.appattest-environment"},
150
+ {"com.apple.developer.associated-domains"},
136
151
  )
137
152
 
138
153
  messages = [c.args[0] for c in printed.call_args_list if c.args]
@@ -145,7 +160,7 @@ class ReconcileTest(unittest.TestCase):
145
160
  mock.patch.object(capabilities, "request", side_effect=RuntimeError("boom")):
146
161
  changed = capabilities.reconcile(
147
162
  "tok", "PK", "com.gowalk.form",
148
- {"com.apple.developer.devicecheck.appattest-environment"},
163
+ {"com.apple.developer.associated-domains"},
149
164
  )
150
165
 
151
166
  self.assertTrue(changed)
@@ -159,7 +174,7 @@ class ReconcileTest(unittest.TestCase):
159
174
  mock.patch.object(capabilities, "request", side_effect=SystemExit("400")):
160
175
  changed = capabilities.reconcile(
161
176
  "tok", "PK", "com.gowalk.form",
162
- {"com.apple.developer.devicecheck.appattest-environment"},
177
+ {"com.apple.developer.associated-domains"},
163
178
  )
164
179
 
165
180
  self.assertTrue(changed)
@@ -1 +1 @@
1
- 1.0.8
1
+ 1.0.9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gowalk-cicd",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Zero-config GitHub Actions delivery for iOS TestFlight and Android Google Play.",
5
5
  "type": "module",
6
6
  "bin": {