Match dev mock to production: reject raw PAN card creation (PCI-DSS parity)
Previously the dev MockClient was more permissive than production: - MockClient.CreateCardOnFileRaw processed raw PANs and stored mock cards, while ProdClient and devProdClient both block raw PANs. A dev testing the raw-card flow saw it succeed, masking a production failure. - MockClient.CreateCardOnFile accepted raw PANs as source_id via an isAllDigits branch. Real Square only accepts cnon:xxx/ccof:xxx tokens. Now the mock behaves identically to production: - CreateCardOnFileRaw returns the same PCI error as ProdClient - CreateCardOnFile validates source_id is token-like (cnon:/ccof:) and rejects raw PANs - Removed dead isAllDigits helper Tests updated to assert the parity behavior: - TestDevClient_CreateCardOnFileRaw_Rejected_ProdParity (table-driven, replaces 5 brand-specific raw-PAN tests) - TestDevClient_CreateCardOnFile_RejectsRawPAN (replaces RawNumber) - TestCreatePaymentMethod_HappyPath / SecondCardNotDefault now expect 500 instead of 200, documenting the prod block
This commit is contained in:
@@ -2153,24 +2153,10 @@ func TestCreatePaymentMethod_HappyPath(t *testing.T) {
|
||||
|
||||
w := makePaymentRequest(handler, "POST", "/api/user/payment-methods", reqBody, token, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
return
|
||||
}
|
||||
|
||||
var card SavedCard
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &card); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
if card.Brand != "VISA" {
|
||||
t.Errorf("expected brand VISA, got %s", card.Brand)
|
||||
}
|
||||
if card.Last4 != "1111" {
|
||||
t.Errorf("expected last4 1111, got %s", card.Last4)
|
||||
}
|
||||
if !card.IsDefault {
|
||||
t.Error("expected first card to be default")
|
||||
// PCI-DSS parity: raw PAN card creation is blocked in production, so the
|
||||
// mock must reject it too — otherwise dev testing masks a prod failure.
|
||||
if w.Code != http.StatusInternalServerError {
|
||||
t.Errorf("expected status 500 (raw PAN rejected), got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2296,7 +2282,8 @@ func TestCreatePaymentMethod_SecondCardNotDefault(t *testing.T) {
|
||||
|
||||
token := jwt.GenerateUserToken(userID)
|
||||
|
||||
// Create first card
|
||||
// PCI-DSS parity: raw PAN card creation is blocked in production, so the
|
||||
// mock must reject it too — otherwise dev testing masks a prod failure.
|
||||
handler := CreatePaymentMethod
|
||||
reqBody := CreatePaymentMethodRequest{
|
||||
CardNumber: "4111111111111111",
|
||||
@@ -2305,31 +2292,8 @@ func TestCreatePaymentMethod_SecondCardNotDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
w := makePaymentRequest(handler, "POST", "/api/user/payment-methods", reqBody, token, ctx)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("failed to create first card: %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
reqBody2 := CreatePaymentMethodRequest{
|
||||
CardNumber: "5500000000000004",
|
||||
Expiry: "06/30",
|
||||
CVC: "456",
|
||||
}
|
||||
|
||||
w = makePaymentRequest(handler, "POST", "/api/user/payment-methods", reqBody2, token, ctx)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("failed to create second card: %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
var card SavedCard
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &card); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
if card.Brand != "MASTERCARD" {
|
||||
t.Errorf("expected brand MASTERCARD, got %s", card.Brand)
|
||||
}
|
||||
if card.IsDefault {
|
||||
t.Error("expected second card to NOT be default")
|
||||
if w.Code != http.StatusInternalServerError {
|
||||
t.Fatalf("expected 500 (raw PAN rejected), got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user