@@ -17,6 +17,7 @@ import { parseJsonOutput } from "../../../../helpers/ndjson.js";
1717describe ( "push:config:set-apns command" , ( ) => {
1818 let appId : string ;
1919 const p8FixturePath = resolve ( "test/fixtures/push/test-apns-key.p8" ) ;
20+ const p12FixturePath = resolve ( "test/fixtures/push/test-apns-cert.p12" ) ;
2021
2122 beforeEach ( ( ) => {
2223 const ctx = getControlApiContext ( ) ;
@@ -67,7 +68,7 @@ describe("push:config:set-apns command", () => {
6768 . reply ( 200 , { id : "cert-123" } ) ;
6869
6970 const { stderr } = await runCommand (
70- [ "push:config:set-apns" , "--certificate" , p8FixturePath ] ,
71+ [ "push:config:set-apns" , "--certificate" , p12FixturePath ] ,
7172 import . meta. url ,
7273 ) ;
7374
@@ -107,7 +108,7 @@ describe("push:config:set-apns command", () => {
107108 . reply ( 200 , { id : "cert-123" } ) ;
108109
109110 const { stdout } = await runCommand (
110- [ "push:config:set-apns" , "--certificate" , p8FixturePath , "--json" ] ,
111+ [ "push:config:set-apns" , "--certificate" , p12FixturePath , "--json" ] ,
111112 import . meta. url ,
112113 ) ;
113114
@@ -206,7 +207,7 @@ describe("push:config:set-apns command", () => {
206207 . reply ( 200 , { id : appId , apnsUseSandboxEndpoint : true } ) ;
207208
208209 const { stderr } = await runCommand (
209- [ "push:config:set-apns" , "--certificate" , p8FixturePath , "--sandbox" ] ,
210+ [ "push:config:set-apns" , "--certificate" , p12FixturePath , "--sandbox" ] ,
210211 import . meta. url ,
211212 ) ;
212213
@@ -223,6 +224,84 @@ describe("push:config:set-apns command", () => {
223224 } ) ;
224225 } ) ;
225226
227+ describe ( "file extension validation" , ( ) => {
228+ it ( "should reject certificate files without .p12 or .pfx extension" , async ( ) => {
229+ const { error } = await runCommand (
230+ [ "push:config:set-apns" , "--certificate" , "/etc/passwd" ] ,
231+ import . meta. url ,
232+ ) ;
233+
234+ expect ( error ) . toBeDefined ( ) ;
235+ expect ( error ?. message ) . toContain ( "Invalid certificate file type" ) ;
236+ expect ( error ?. message ) . toContain ( ".p12 or .pfx" ) ;
237+ } ) ;
238+
239+ it ( "should reject key files without .p8 extension" , async ( ) => {
240+ const { error } = await runCommand (
241+ [
242+ "push:config:set-apns" ,
243+ "--key-file" ,
244+ "/some/file.txt" ,
245+ "--key-id" ,
246+ "KEY123" ,
247+ "--team-id" ,
248+ "TEAM456" ,
249+ "--topic" ,
250+ "com.example.app" ,
251+ ] ,
252+ import . meta. url ,
253+ ) ;
254+
255+ expect ( error ) . toBeDefined ( ) ;
256+ expect ( error ?. message ) . toContain ( "Invalid key file type" ) ;
257+ expect ( error ?. message ) . toContain ( ".p8" ) ;
258+ } ) ;
259+
260+ it ( "should accept .pfx certificate files" , async ( ) => {
261+ nockControl ( )
262+ . post ( `/v1/apps/${ appId } /pkcs12` )
263+ . reply ( 200 , { id : "cert-123" } ) ;
264+
265+ // The file won't exist, but extension validation should pass
266+ const { error } = await runCommand (
267+ [ "push:config:set-apns" , "--certificate" , "/nonexistent/cert.pfx" ] ,
268+ import . meta. url ,
269+ ) ;
270+
271+ // Should fail with "not found", not "invalid file type"
272+ expect ( error ) . toBeDefined ( ) ;
273+ expect ( error ?. message ) . toContain ( "not found" ) ;
274+ } ) ;
275+ } ) ;
276+
277+ describe ( "web CLI restrictions" , ( ) => {
278+ let originalWebCliMode : string | undefined ;
279+
280+ beforeEach ( ( ) => {
281+ originalWebCliMode = process . env . ABLY_WEB_CLI_MODE ;
282+ } ) ;
283+
284+ afterEach ( ( ) => {
285+ if ( originalWebCliMode === undefined ) {
286+ delete process . env . ABLY_WEB_CLI_MODE ;
287+ } else {
288+ process . env . ABLY_WEB_CLI_MODE = originalWebCliMode ;
289+ }
290+ } ) ;
291+
292+ it ( "should be restricted in web CLI mode" , async ( ) => {
293+ process . env . ABLY_WEB_CLI_MODE = "true" ;
294+
295+ const { error } = await runCommand (
296+ [ "push:config:set-apns" , "--certificate" , p12FixturePath ] ,
297+ import . meta. url ,
298+ ) ;
299+
300+ expect ( error ) . toBeDefined ( ) ;
301+ expect ( error ?. message ) . toContain ( "not available in the web CLI" ) ;
302+ } ) ;
303+ } ) ;
304+
226305 describe ( "error handling" , ( ) => {
227306 standardControlApiErrorTests ( {
228307 commandArgs : [
0 commit comments