@sungen/driver-data-factory 3.2.10-beta.6 → 3.2.12-beta.10
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/common/experience/auth-account-states.yaml +19 -0
- package/common/field-types/currency.yaml +10 -10
- package/common/field-types/email.yaml +19 -16
- package/common/field-types/jp/katakana.yaml +12 -12
- package/common/field-types/number-float.yaml +10 -10
- package/common/field-types/number-integer.yaml +12 -12
- package/common/field-types/password.yaml +22 -22
- package/common/field-types/phone.yaml +14 -14
- package/common/field-types/postcode.yaml +8 -8
- package/common/field-types/string.yaml +11 -11
- package/common/security/broken-auth.yaml +6 -6
- package/common/security/idor.yaml +5 -5
- package/common/security/input-validation.yaml +5 -5
- package/common/security/sqli.yaml +7 -7
- package/common/security/upload.yaml +7 -7
- package/common/security/xss.yaml +9 -9
- package/common/techniques/boundary.yaml +4 -4
- package/common/techniques/decision-table.yaml +4 -4
- package/common/techniques/equivalence.yaml +4 -4
- package/common/techniques/state-transition.yaml +4 -4
- package/package.json +3 -3
- package/src/applicability.ts +80 -0
- package/src/boundary.ts +319 -0
- package/src/catalog-loader.ts +104 -18
- package/src/cli.ts +233 -14
- package/src/contract.ts +93 -0
- package/src/crosscheck.ts +149 -0
- package/src/detect.ts +122 -0
- package/src/fixture.ts +111 -0
- package/src/generator.ts +231 -98
- package/src/index.ts +17 -2
- package/src/lint.ts +31 -16
- package/src/readme.ts +52 -0
- package/src/sensor.ts +32 -4
- package/src/state.ts +225 -0
- package/src/types.ts +82 -1
- package/src/validate.ts +77 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Experience checklist: authentication credential / account states — from real login-testing experience.
|
|
2
|
+
# These are LOGIN/AUTH *scenarios*, NOT field-format data: each case is a credential pair whose ACCOUNT
|
|
3
|
+
# is in a particular state, with an expected auth outcome. Most need a domain-state PRECONDITION (a
|
|
4
|
+
# seeded account in that state) — declare it with a state-recipe (`sungen data state`) so it renders a
|
|
5
|
+
# @manual:data-setup Background. Data Factory carries this knowledge; create-test's login viewpoint
|
|
6
|
+
# generates the scenarios. Confirm the exact outcome/message code with the spec/BA — never assume.
|
|
7
|
+
experience: auth-account-states
|
|
8
|
+
description: Credential/account states a login (email+password or credential form) screen must cover.
|
|
9
|
+
applies_when: "a login / sign-in / authentication screen (credential form)"
|
|
10
|
+
cases:
|
|
11
|
+
- { id: CHK-AUTH-01, state: active, expect: "login succeeds → authenticated destination", note: "happy path — a valid ACTIVE account" }
|
|
12
|
+
- { id: CHK-AUTH-02, state: wrong-password, expect: "auth fails with a generic error (no user-enumeration)" }
|
|
13
|
+
- { id: CHK-AUTH-03, state: non-existent-account, expect: "auth fails with the SAME generic error as wrong-password (don't reveal which is wrong)" }
|
|
14
|
+
- { id: CHK-AUTH-04, state: soft-deleted, expect: "login REJECTED — a soft-deleted account must NOT authenticate", note: "real-world bug precedent: soft-deleted rows still passing auth because the query didn't filter deleted_at" }
|
|
15
|
+
- { id: CHK-AUTH-05, state: locked-or-suspended, expect: "login blocked with a locked/suspended message (not the generic auth error)" }
|
|
16
|
+
- { id: CHK-AUTH-06, state: unverified-email, expect: "login blocked or routed to verification, per spec" }
|
|
17
|
+
- { id: CHK-AUTH-07, state: password-expired, expect: "routed to password reset / forced change, per spec" }
|
|
18
|
+
- { id: CHK-AUTH-08, state: valid-with-surrounding-whitespace, expect: "email trimmed then login succeeds (pair a valid account email with leading/trailing spaces)", note: "trim behaviour — see the email field-type CHK-EMAIL-WS" }
|
|
19
|
+
oracle: "Each non-happy state needs a seeded account IN that state (a domain-state precondition / fixture). The 'wrong-password' and 'non-existent' outcomes should be indistinguishable (anti-enumeration). soft-deleted / locked / unverified / expired must each be blocked with the correct, spec-defined outcome."
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Field-type: currency (money) — from common-checklist.xlsx (Input box · Currency).
|
|
2
2
|
type: currency
|
|
3
|
-
description:
|
|
3
|
+
description: Money amount — integer/decimal per currency unit; watch leading-zero & the value 0.
|
|
4
4
|
constraints:
|
|
5
5
|
min: 0
|
|
6
6
|
max: 999999999 # placeholder
|
|
7
|
-
decimalPlaces: 0 # placeholder (JPY=0, USD=2
|
|
7
|
+
decimalPlaces: 0 # placeholder (JPY=0, USD=2 ...)
|
|
8
8
|
valid:
|
|
9
|
-
- { id: CHK-CUR-01, value: "1000", note: "
|
|
10
|
-
- { id: CHK-CUR-02, value: "0", note: "
|
|
9
|
+
- { id: CHK-CUR-01, value: "1000", note: "valid amount" }
|
|
10
|
+
- { id: CHK-CUR-02, value: "0", note: "0 must mean 0, NOT 'not entered'" }
|
|
11
11
|
boundary:
|
|
12
|
-
- { id: CHK-CUR-B1, gen: "
|
|
13
|
-
- { id: CHK-CUR-B2, gen: "
|
|
12
|
+
- { id: CHK-CUR-B1, gen: "min / min+1" }
|
|
13
|
+
- { id: CHK-CUR-B2, gen: "max / max-1" }
|
|
14
14
|
invalid:
|
|
15
|
-
- { id: CHK-CUR-I1, gen: "
|
|
16
|
-
- { id: CHK-CUR-I2, gen: "
|
|
17
|
-
- { id: CHK-CUR-I3, value: "", reason: "
|
|
15
|
+
- { id: CHK-CUR-I1, gen: "alphabetic / stray characters", reason: "not a number", errorRef: M13 }
|
|
16
|
+
- { id: CHK-CUR-I2, gen: "min-1 / max+1", reason: "out of bounds", errorRef: M13 }
|
|
17
|
+
- { id: CHK-CUR-I3, value: "", reason: "empty (per spec)", errorRef: M02, when: { required: true } }
|
|
18
18
|
notes:
|
|
19
|
-
- "
|
|
19
|
+
- "Check separately: leading zero (0100) not stripped; thousands separator display format."
|
|
20
20
|
uses_security: [sqli]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Field-type: email — seeded from common-checklist.xlsx (Input box · Email) +
|
|
1
|
+
# Field-type: email — seeded from common-checklist.xlsx (Input box · Email) + the 4-source method.
|
|
2
2
|
# errorRef (Mxx) are PLACEHOLDERS — the generator maps them onto the project's real message codes;
|
|
3
|
-
# if the project spec has none, the value is marked as
|
|
3
|
+
# if the project spec has none, the value is marked as an open point, not invented.
|
|
4
4
|
type: email
|
|
5
|
-
description:
|
|
5
|
+
description: Half-width email, format <local-part>@<domain>.
|
|
6
6
|
format: "<local-part>@<domain>"
|
|
7
7
|
constraints:
|
|
8
8
|
charset: half-width
|
|
@@ -13,18 +13,21 @@ valid:
|
|
|
13
13
|
- { id: CHK-EMAIL-01, value: "user@example.com", note: "normal half-width" }
|
|
14
14
|
- { id: CHK-EMAIL-02, value: "u.name+tag@sub.example.co.jp", note: "dotted local + subdomain" }
|
|
15
15
|
boundary:
|
|
16
|
-
- { id: CHK-EMAIL-B1, gen: "local
|
|
17
|
-
- { id: CHK-EMAIL-B2, gen: "local
|
|
18
|
-
- { id: CHK-EMAIL-B3, gen: "
|
|
16
|
+
- { id: CHK-EMAIL-B1, gen: "local part = maxLocal", note: "local part = max (64)" }
|
|
17
|
+
- { id: CHK-EMAIL-B2, gen: "local part = maxLocal-1", note: "local part = max-1" }
|
|
18
|
+
- { id: CHK-EMAIL-B3, gen: "total = maxTotal", note: "total length = max (255)" }
|
|
19
|
+
# min-length side (total = minLength / minLength±1) is auto-completed by the BVA pass from the
|
|
20
|
+
# field-map's `minLength` — see ensureBvaComplete; no gen entry needed here.
|
|
21
|
+
- { id: CHK-EMAIL-WS, value: " user@example.com ", validity: valid, note: "leading/trailing whitespace — server MUST trim then accept (pair with a valid password); if the spec rejects instead, override validity to invalid" }
|
|
19
22
|
invalid:
|
|
20
|
-
- { id: CHK-EMAIL-I1, value: "user@", reason: "
|
|
21
|
-
- { id: CHK-EMAIL-I2, value: "user@.com", reason: "
|
|
22
|
-
- { id: CHK-EMAIL-I3, value: "u@@b.com", reason: "
|
|
23
|
-
- { id: CHK-EMAIL-I4, value: "@example.com", reason: "
|
|
24
|
-
- { id: CHK-EMAIL-I5, value: "user@example.com", reason: "full-width
|
|
25
|
-
- { id: CHK-EMAIL-I6, gen: "local >
|
|
26
|
-
- { id: CHK-EMAIL-I7, gen: "
|
|
27
|
-
- { id: CHK-EMAIL-I8, value: "", reason: "
|
|
23
|
+
- { id: CHK-EMAIL-I1, value: "user@", reason: "missing domain", errorRef: M13 }
|
|
24
|
+
- { id: CHK-EMAIL-I2, value: "user@.com", reason: "dot in wrong position", errorRef: M13 }
|
|
25
|
+
- { id: CHK-EMAIL-I3, value: "u@@b.com", reason: "two @ signs", errorRef: M13 }
|
|
26
|
+
- { id: CHK-EMAIL-I4, value: "@example.com", reason: "missing local-part", errorRef: M13 }
|
|
27
|
+
- { id: CHK-EMAIL-I5, value: "user@example.com", reason: "full-width characters", errorRef: M39 }
|
|
28
|
+
- { id: CHK-EMAIL-I6, gen: "local > maxLocal", reason: "exceeds maxLocal", errorRef: M13 }
|
|
29
|
+
- { id: CHK-EMAIL-I7, gen: "total > maxTotal", reason: "exceeds maxTotal", errorRef: M13 }
|
|
30
|
+
- { id: CHK-EMAIL-I8, value: "", reason: "empty (required)", errorRef: M02, when: { required: true } }
|
|
28
31
|
notes:
|
|
29
|
-
- "
|
|
30
|
-
- "Soft-delete:
|
|
32
|
+
- "Normalize: lowercase, NFKC, trim before comparison."
|
|
33
|
+
- "Soft-delete: if a deleted email gets a suffix appended, test maxTotal LOWER than the DB column limit to leave room for the suffix."
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# Field-type: Katakana name (JP-specific) — from
|
|
1
|
+
# Field-type: Katakana name (JP-specific) — from the 4-source method (JP field-type experience).
|
|
2
2
|
type: katakana
|
|
3
|
-
description:
|
|
3
|
+
description: Katakana-only field (kana name in Japanese systems).
|
|
4
4
|
constraints:
|
|
5
5
|
charset: "full-width Katakana only"
|
|
6
6
|
valid:
|
|
7
|
-
- { id: CHK-KANA-01, value: "ヤマダ", note: "Katakana
|
|
8
|
-
- { id: CHK-KANA-02, value: "ジョウジ", note: "
|
|
7
|
+
- { id: CHK-KANA-01, value: "ヤマダ", note: "standard Katakana" }
|
|
8
|
+
- { id: CHK-KANA-02, value: "ジョウジ", note: "valid dakuten + long-vowel mark" }
|
|
9
9
|
boundary:
|
|
10
|
-
- { id: CHK-KANA-B1, gen: "
|
|
10
|
+
- { id: CHK-KANA-B1, gen: "min / max length" }
|
|
11
11
|
invalid:
|
|
12
|
-
- { id: CHK-KANA-I1, value: "yamada", reason: "
|
|
13
|
-
- { id: CHK-KANA-I2, value: "やまだ", reason: "
|
|
14
|
-
- { id: CHK-KANA-I3, value: "山田", reason: "
|
|
15
|
-
- { id: CHK-KANA-I4, value: "ヤマダ", reason: "half-width kana (
|
|
16
|
-
- { id: CHK-KANA-I5, value: "ゝ々", reason: "
|
|
17
|
-
- { id: CHK-KANA-I6, value: "ャュョ", reason: "kana
|
|
12
|
+
- { id: CHK-KANA-I1, value: "yamada", reason: "Latin characters mixed in", errorRef: M39 }
|
|
13
|
+
- { id: CHK-KANA-I2, value: "やまだ", reason: "Hiragana mixed in", errorRef: M39 }
|
|
14
|
+
- { id: CHK-KANA-I3, value: "山田", reason: "Kanji mixed in", errorRef: M39 }
|
|
15
|
+
- { id: CHK-KANA-I4, value: "ヤマダ", reason: "half-width kana (if spec requires full-width)", errorRef: M39 }
|
|
16
|
+
- { id: CHK-KANA-I5, value: "ゝ々", reason: "iteration marks — real-world bug precedent in many systems", errorRef: M39 }
|
|
17
|
+
- { id: CHK-KANA-I6, value: "ャュョ", reason: "small kana standalone / wrong position", errorRef: M39 }
|
|
18
18
|
notes:
|
|
19
|
-
- "
|
|
19
|
+
- "Watch: small kana (ゃゅょ), long-vowel mark (ー), dakuten/handakuten, half<->full-width kana."
|
|
20
20
|
uses_security: [sqli, xss]
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# Field-type: number (float) — from common-checklist.xlsx (Input box · Number_Float).
|
|
2
2
|
type: number-float
|
|
3
|
-
description:
|
|
3
|
+
description: Decimal number — digits + decimal separator; decimal places per spec.
|
|
4
4
|
constraints:
|
|
5
5
|
min: 0.0 # placeholder
|
|
6
6
|
max: 999999.99 # placeholder
|
|
7
7
|
decimalPlaces: 2 # placeholder
|
|
8
8
|
valid:
|
|
9
|
-
- { id: CHK-FLOAT-01, value: "123.45", note: "
|
|
10
|
-
- { id: CHK-FLOAT-02, value: "0.5", note: "
|
|
9
|
+
- { id: CHK-FLOAT-01, value: "123.45", note: "valid" }
|
|
10
|
+
- { id: CHK-FLOAT-02, value: "0.5", note: "integer part = 0" }
|
|
11
11
|
boundary:
|
|
12
|
-
- { id: CHK-FLOAT-B1, gen: "
|
|
13
|
-
- { id: CHK-FLOAT-B2, gen: "
|
|
14
|
-
- { id: CHK-FLOAT-B3, gen: "
|
|
12
|
+
- { id: CHK-FLOAT-B1, gen: "min / min+1" }
|
|
13
|
+
- { id: CHK-FLOAT-B2, gen: "max / max-1" }
|
|
14
|
+
- { id: CHK-FLOAT-B3, gen: "exact decimal places / one extra digit" }
|
|
15
15
|
invalid:
|
|
16
|
-
- { id: CHK-FLOAT-I1, gen: "
|
|
17
|
-
- { id: CHK-FLOAT-I2, gen: "format
|
|
18
|
-
- { id: CHK-FLOAT-I3, gen: "
|
|
19
|
-
- { id: CHK-FLOAT-I4, value: "", reason: "
|
|
16
|
+
- { id: CHK-FLOAT-I1, gen: "alphabetic characters", reason: "not a number", errorRef: M13 }
|
|
17
|
+
- { id: CHK-FLOAT-I2, gen: "wrong format (multiple dots, +/- wrong position)", reason: "wrong format", errorRef: M13 }
|
|
18
|
+
- { id: CHK-FLOAT-I3, gen: "min-1 / max+1", reason: "out of bounds", errorRef: M13 }
|
|
19
|
+
- { id: CHK-FLOAT-I4, value: "", reason: "empty/multi-space (per spec)", errorRef: M02, when: { required: true } }
|
|
20
20
|
uses_security: [sqli]
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# Field-type: number (integer) — from common-checklist.xlsx (Input box · Number_Integer).
|
|
2
2
|
type: number-integer
|
|
3
|
-
description:
|
|
3
|
+
description: Integer — digits only, optional +/- in valid position.
|
|
4
4
|
constraints:
|
|
5
|
-
min: 0 # placeholder
|
|
5
|
+
min: 0 # placeholder per spec
|
|
6
6
|
max: 2147483647 # placeholder
|
|
7
7
|
valid:
|
|
8
|
-
- { id: CHK-INT-01, value: "123", note: "
|
|
9
|
-
- { id: CHK-INT-02, value: "-45", note: "
|
|
8
|
+
- { id: CHK-INT-01, value: "123", note: "digits only" }
|
|
9
|
+
- { id: CHK-INT-02, value: "-45", note: "leading - (if spec allows negatives)", when: { negativesAllowed: true } }
|
|
10
10
|
boundary:
|
|
11
|
-
- { id: CHK-INT-B1, gen: "
|
|
12
|
-
- { id: CHK-INT-B2, gen: "
|
|
11
|
+
- { id: CHK-INT-B1, gen: "min / min+1" }
|
|
12
|
+
- { id: CHK-INT-B2, gen: "max / max-1" }
|
|
13
13
|
invalid:
|
|
14
|
-
- { id: CHK-INT-I1, gen: "
|
|
15
|
-
- { id: CHK-INT-I2, gen: "
|
|
16
|
-
- { id: CHK-INT-I3, gen: "+/-
|
|
17
|
-
- { id: CHK-INT-I4, gen: "
|
|
18
|
-
- { id: CHK-INT-I5, value: "", reason: "
|
|
14
|
+
- { id: CHK-INT-I1, gen: "alphabetic characters", reason: "not a number", errorRef: M13 }
|
|
15
|
+
- { id: CHK-INT-I2, gen: "full-width (Japanese) digits", reason: "full-width characters", errorRef: M39 }
|
|
16
|
+
- { id: CHK-INT-I3, gen: "+/- in wrong position (mid-string)", reason: "wrong format", errorRef: M13 }
|
|
17
|
+
- { id: CHK-INT-I4, gen: "min-1 / max+1", reason: "out of bounds", errorRef: M13 }
|
|
18
|
+
- { id: CHK-INT-I5, value: "", reason: "empty/multi-space (per spec)", errorRef: M02, when: { required: true } }
|
|
19
19
|
notes:
|
|
20
|
-
- "leading zero (007)
|
|
20
|
+
- "Check leading zero (007) is not stripped; redundant spaces before/after handled correctly."
|
|
21
21
|
uses_security: [sqli]
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# Field-type: password —
|
|
1
|
+
# Field-type: password — from common-checklist.xlsx (Input box · Password).
|
|
2
2
|
type: password
|
|
3
|
-
description: Password —
|
|
4
|
-
format: "
|
|
3
|
+
description: Password — length + character-class rules per spec; plus show/hide + mask.
|
|
4
|
+
format: "per spec (min/max, >=1 upper/lower/digit as required)"
|
|
5
5
|
constraints:
|
|
6
|
-
minLength: 7 # placeholder —
|
|
6
|
+
minLength: 7 # placeholder — override with the project spec's real min
|
|
7
7
|
maxLength: 20 # placeholder
|
|
8
|
-
requires: [uppercase, lowercase, digit] # placeholder
|
|
8
|
+
requires: [uppercase, lowercase, digit] # placeholder per spec
|
|
9
9
|
uses_security: [sqli, xss]
|
|
10
10
|
valid:
|
|
11
|
-
- { id: CHK-PW-01, value: "Passw0rd", note: "
|
|
12
|
-
- { id: CHK-PW-02, note: "alpha only / numeric only / mix —
|
|
13
|
-
- { id: CHK-PW-03, note: "
|
|
11
|
+
- { id: CHK-PW-01, value: "Passw0rd", note: "upper+lower+digit, in range" }
|
|
12
|
+
- { id: CHK-PW-02, note: "alpha only / numeric only / mix — if the spec allows" }
|
|
13
|
+
- { id: CHK-PW-03, note: "valid special characters per spec (e.g. ._@)" }
|
|
14
14
|
boundary:
|
|
15
|
-
- { id: CHK-PW-B1, gen: "
|
|
16
|
-
- { id: CHK-PW-B2, gen: "
|
|
17
|
-
- { id: CHK-PW-B3, gen: "
|
|
18
|
-
- { id: CHK-PW-B4, gen: "
|
|
15
|
+
- { id: CHK-PW-B1, gen: "min length", note: "min (e.g. Aa1bcde = 7)" }
|
|
16
|
+
- { id: CHK-PW-B2, gen: "min+1", note: "min+1" }
|
|
17
|
+
- { id: CHK-PW-B3, gen: "max length", note: "max" }
|
|
18
|
+
- { id: CHK-PW-B4, gen: "max-1", note: "max-1" }
|
|
19
19
|
invalid:
|
|
20
|
-
- { id: CHK-PW-I1, value: "", reason: "
|
|
21
|
-
- { id: CHK-PW-I2, gen: "<
|
|
22
|
-
- { id: CHK-PW-I3, gen: ">
|
|
23
|
-
- { id: CHK-PW-I4, value: "passw0rd", reason: "
|
|
24
|
-
- { id: CHK-PW-I5, value: "PASSW0RD", reason: "
|
|
25
|
-
- { id: CHK-PW-I6, value: "Password", reason: "
|
|
26
|
-
- { id: CHK-PW-I7, gen: "full-width Japanese", reason: "
|
|
27
|
-
- { id: CHK-PW-I8, gen: "space before/after
|
|
20
|
+
- { id: CHK-PW-I1, value: "", reason: "empty/multi-space (required)", errorRef: M02, when: { required: true } }
|
|
21
|
+
- { id: CHK-PW-I2, gen: "< min length", reason: "below minimum length", errorRef: M29 }
|
|
22
|
+
- { id: CHK-PW-I3, gen: "> max length", reason: "exceeds maximum length", errorRef: M30 }
|
|
23
|
+
- { id: CHK-PW-I4, value: "passw0rd", reason: "missing uppercase", errorRef: M31 }
|
|
24
|
+
- { id: CHK-PW-I5, value: "PASSW0RD", reason: "missing lowercase", errorRef: M32 }
|
|
25
|
+
- { id: CHK-PW-I6, value: "Password", reason: "missing digit", errorRef: M33 }
|
|
26
|
+
- { id: CHK-PW-I7, gen: "full-width Japanese", reason: "full-width characters", errorRef: M39 }
|
|
27
|
+
- { id: CHK-PW-I8, gen: "space before/after or inside", reason: "redundant whitespace", errorRef: M13 }
|
|
28
28
|
notes:
|
|
29
|
-
- "
|
|
30
|
-
- "Confirm Password:
|
|
29
|
+
- "Check separately: show/hide password icon (display + toggle mask<->unmask), mask symbol per spec."
|
|
30
|
+
- "Confirm Password: inherits all password cases + (confirm == password) and (confirm != password -> error)."
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
# Field-type: phone number — from common-checklist.xlsx (Input box · Phone number).
|
|
2
2
|
type: phone
|
|
3
|
-
description:
|
|
3
|
+
description: Phone number — digits only, allows () - + in valid positions.
|
|
4
4
|
constraints:
|
|
5
5
|
charset: "digits + () - +"
|
|
6
|
-
minLength: 8 # placeholder
|
|
6
|
+
minLength: 8 # placeholder per spec
|
|
7
7
|
maxLength: 15 # placeholder
|
|
8
8
|
valid:
|
|
9
|
-
- { id: CHK-PHONE-01, value: "0987654321", note: "
|
|
10
|
-
- { id: CHK-PHONE-02, value: "+84-90-1234567", note: "
|
|
11
|
-
- { id: CHK-PHONE-03, value: "(028)38221234", note: "
|
|
9
|
+
- { id: CHK-PHONE-01, value: "0987654321", note: "digits only" }
|
|
10
|
+
- { id: CHK-PHONE-02, value: "+84-90-1234567", note: "+ and - in valid positions" }
|
|
11
|
+
- { id: CHK-PHONE-03, value: "(028)38221234", note: "() in valid positions" }
|
|
12
12
|
boundary:
|
|
13
|
-
- { id: CHK-PHONE-B1, gen: "
|
|
14
|
-
- { id: CHK-PHONE-B2, gen: "
|
|
13
|
+
- { id: CHK-PHONE-B1, gen: "min / min+1 length" }
|
|
14
|
+
- { id: CHK-PHONE-B2, gen: "max / max-1 length" }
|
|
15
15
|
invalid:
|
|
16
|
-
- { id: CHK-PHONE-I1, gen: "
|
|
17
|
-
- { id: CHK-PHONE-I2, gen: "
|
|
18
|
-
- { id: CHK-PHONE-I3, gen: "
|
|
19
|
-
- { id: CHK-PHONE-I4, value: "090 123 4567", reason: "
|
|
20
|
-
- { id: CHK-PHONE-I5, gen: "+/-
|
|
21
|
-
- { id: CHK-PHONE-I6, gen: "min-1 / max+1", reason: "
|
|
22
|
-
- { id: CHK-PHONE-I7, value: "", reason: "
|
|
16
|
+
- { id: CHK-PHONE-I1, gen: "forbidden chars []:,;\"<>\\?", reason: "invalid characters", errorRef: M13 }
|
|
17
|
+
- { id: CHK-PHONE-I2, gen: "full-width (Japanese) digits", reason: "full-width characters", errorRef: M39 }
|
|
18
|
+
- { id: CHK-PHONE-I3, gen: "alphabetic characters", reason: "not a number", errorRef: M13 }
|
|
19
|
+
- { id: CHK-PHONE-I4, value: "090 123 4567", reason: "spaces between digits", errorRef: M13 }
|
|
20
|
+
- { id: CHK-PHONE-I5, gen: "+/- not first; () wrong position", reason: "wrong format", errorRef: M13 }
|
|
21
|
+
- { id: CHK-PHONE-I6, gen: "min-1 / max+1", reason: "out of bounds", errorRef: M13 }
|
|
22
|
+
- { id: CHK-PHONE-I7, value: "", reason: "empty/multi-space (per spec)", errorRef: M02, when: { required: true } }
|
|
23
23
|
uses_security: [sqli]
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Field-type: postcode / zipcode — from common-checklist.xlsx (Input box · Postcode/Zipcode).
|
|
2
2
|
type: postcode
|
|
3
|
-
description:
|
|
3
|
+
description: Postal code — region-specific format (JP 7 digits, optional -).
|
|
4
4
|
constraints:
|
|
5
|
-
format: "region-specific (
|
|
5
|
+
format: "region-specific (e.g. JP: NNN-NNNN)"
|
|
6
6
|
length: 7 # placeholder
|
|
7
7
|
valid:
|
|
8
|
-
- { id: CHK-ZIP-01, value: "1500001", note: "7
|
|
9
|
-
- { id: CHK-ZIP-02, value: "150-0001", note: "
|
|
8
|
+
- { id: CHK-ZIP-01, value: "1500001", note: "7 digits (JP)" }
|
|
9
|
+
- { id: CHK-ZIP-02, value: "150-0001", note: "with - if the spec allows" }
|
|
10
10
|
boundary:
|
|
11
|
-
- { id: CHK-ZIP-B1, gen: "
|
|
11
|
+
- { id: CHK-ZIP-B1, gen: "exact length / length-1 / +1" }
|
|
12
12
|
invalid:
|
|
13
|
-
- { id: CHK-ZIP-I1, gen: "
|
|
14
|
-
- { id: CHK-ZIP-I2, gen: "
|
|
15
|
-
- { id: CHK-ZIP-I3, value: "", reason: "
|
|
13
|
+
- { id: CHK-ZIP-I1, gen: "alphabetic / stray characters", reason: "invalid characters", errorRef: M13 }
|
|
14
|
+
- { id: CHK-ZIP-I2, gen: "wrong region format", reason: "wrong format", errorRef: M13 }
|
|
15
|
+
- { id: CHK-ZIP-I3, value: "", reason: "empty (per spec)", errorRef: M02, when: { required: true } }
|
|
16
16
|
uses_security: [sqli]
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# Field-type: string (
|
|
1
|
+
# Field-type: string (single line) — from common-checklist.xlsx (Input box · String).
|
|
2
2
|
type: string
|
|
3
|
-
description:
|
|
3
|
+
description: Single-line string — accepts alnum, JP half/full-width, special chars, unicode, spaces.
|
|
4
4
|
constraints:
|
|
5
|
-
minLength: 1 # placeholder
|
|
5
|
+
minLength: 1 # placeholder per spec
|
|
6
6
|
maxLength: 255 # placeholder
|
|
7
7
|
uses_security: [sqli, xss]
|
|
8
8
|
valid:
|
|
9
9
|
- { id: CHK-STR-01, value: "Normal text 123", note: "alnum + space" }
|
|
10
|
-
- { id: CHK-STR-02, gen: "half-width Japanese", note: "
|
|
10
|
+
- { id: CHK-STR-02, gen: "half-width Japanese", note: "パカナ" }
|
|
11
11
|
- { id: CHK-STR-03, gen: "full-width Japanese", note: "全角かな漢字" }
|
|
12
|
-
- { id: CHK-STR-04, gen: "special chars ~!@#$%^&*()_+{}:|<>?,./;'[]-=`", note: "
|
|
13
|
-
- { id: CHK-STR-05, gen: "unicode / emoji
|
|
14
|
-
- { id: CHK-STR-06, gen: "copy-paste full-width JP", note: "
|
|
12
|
+
- { id: CHK-STR-04, gen: "special chars ~!@#$%^&*()_+{}:|<>?,./;'[]-=`", note: "valid special characters" }
|
|
13
|
+
- { id: CHK-STR-05, gen: "unicode / emoji if the spec allows" }
|
|
14
|
+
- { id: CHK-STR-06, gen: "copy-paste full-width JP", note: "must handle paste correctly" }
|
|
15
15
|
boundary:
|
|
16
|
-
- { id: CHK-STR-B1, gen: "
|
|
17
|
-
- { id: CHK-STR-B2, gen: "
|
|
16
|
+
- { id: CHK-STR-B1, gen: "min / min+1 length" }
|
|
17
|
+
- { id: CHK-STR-B2, gen: "max / max-1 length" }
|
|
18
18
|
invalid:
|
|
19
|
-
- { id: CHK-STR-I1, value: "", reason: "
|
|
20
|
-
- { id: CHK-STR-I2, gen: "min-1 / max+1", reason: "
|
|
19
|
+
- { id: CHK-STR-I1, value: "", reason: "empty/multi-space (success/fail per spec)", errorRef: M02, when: { required: true } }
|
|
20
|
+
- { id: CHK-STR-I2, gen: "min-1 / max+1", reason: "out of bounds", errorRef: M13 }
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Security payload bank: Broken authentication — from common-checklist.xlsx (Broken authentication).
|
|
2
2
|
class: broken-auth
|
|
3
|
-
description:
|
|
3
|
+
description: Weak authentication — session/token/brute-force.
|
|
4
4
|
payloads:
|
|
5
|
-
- { id: CHK-SEC-AUTH-01, technique: "brute
|
|
6
|
-
- { id: CHK-SEC-AUTH-02, technique: "session
|
|
7
|
-
- { id: CHK-SEC-AUTH-03, technique: "session fixation —
|
|
8
|
-
- { id: CHK-SEC-AUTH-04, technique: "
|
|
9
|
-
oracle: "
|
|
5
|
+
- { id: CHK-SEC-AUTH-01, technique: "unlimited brute-force login", expect: "lockout/captcha/rate-limit present" }
|
|
6
|
+
- { id: CHK-SEC-AUTH-02, technique: "session not expired after logout / password change", expect: "old session invalidated" }
|
|
7
|
+
- { id: CHK-SEC-AUTH-03, technique: "session fixation — reuse the pre-login session id", expect: "issues a new session after login" }
|
|
8
|
+
- { id: CHK-SEC-AUTH-04, technique: "guessable / non-expiring token", expect: "strong random token with a TTL" }
|
|
9
|
+
oracle: "Unauthorized login / session persistence = a vulnerability."
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Security payload bank: IDOR — from common-checklist.xlsx (Insecure Direct Object Reference).
|
|
2
2
|
class: idor
|
|
3
|
-
description: Insecure Direct Object Reference —
|
|
3
|
+
description: Insecure Direct Object Reference — change an id to access another user's resource.
|
|
4
4
|
payloads:
|
|
5
|
-
- { id: CHK-SEC-IDOR-01, technique: "
|
|
6
|
-
- { id: CHK-SEC-IDOR-02, technique: "
|
|
7
|
-
- { id: CHK-SEC-IDOR-03, technique: "
|
|
8
|
-
oracle: "
|
|
5
|
+
- { id: CHK-SEC-IDOR-01, technique: "change the id in URL/param to another user's record", expect: "403/404, does NOT leak the other user's data" }
|
|
6
|
+
- { id: CHK-SEC-IDOR-02, technique: "guess sequential ids (1,2,3...) on a detail API", expect: "checks ownership, rejects" }
|
|
7
|
+
- { id: CHK-SEC-IDOR-03, technique: "act (edit/delete) on a resource outside your scope via id", expect: "blocked server-side, not just hidden in the UI" }
|
|
8
|
+
oracle: "Reading/modifying data outside your scope = a vulnerability. Expected: ownership authorization server-side."
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Security payload bank: Input validation — from common-checklist.xlsx (Input validation).
|
|
2
2
|
class: input-validation
|
|
3
|
-
description:
|
|
3
|
+
description: Server-side input constraints (not just the front-end).
|
|
4
4
|
payloads:
|
|
5
|
-
- { id: CHK-SEC-IV-01, technique: "
|
|
6
|
-
- { id: CHK-SEC-IV-02, technique: "
|
|
7
|
-
- { id: CHK-SEC-IV-03, technique: "control/null bytes,
|
|
8
|
-
oracle: "FE
|
|
5
|
+
- { id: CHK-SEC-IV-01, technique: "exceed boundary when the FE is bypassed (call the API directly)", expect: "the server rejects too" }
|
|
6
|
+
- { id: CHK-SEC-IV-02, technique: "wrong data type (string into a numeric field)", expect: "rejects with a valid error" }
|
|
7
|
+
- { id: CHK-SEC-IV-03, technique: "control/null bytes, control characters", expect: "stripped/rejected" }
|
|
8
|
+
oracle: "The FE may pass but the BE must reject — test the API directly, bypassing the FE."
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Security payload bank: SQL Injection — from common-checklist.xlsx (SQL Injection sheet).
|
|
2
2
|
# Reusable adversarial values injected into the `invalid` group of any field via uses_security: [sqli].
|
|
3
3
|
class: sqli
|
|
4
|
-
description: SQL Injection —
|
|
4
|
+
description: SQL Injection — inputs crafted to break the query / bypass authentication.
|
|
5
5
|
payloads:
|
|
6
|
-
- { id: CHK-SEC-SQLI-01, value: "admin' --", target: "login username", expect: "
|
|
7
|
-
- { id: CHK-SEC-SQLI-02, value: "test' OR '1'='1", target: "
|
|
8
|
-
- { id: CHK-SEC-SQLI-03, value: "test@test.com' OR '1'='1", target: "email
|
|
9
|
-
- { id: CHK-SEC-SQLI-04, value: "test', isAdmin = 1 --", target: "
|
|
10
|
-
- { id: CHK-SEC-SQLI-05, value: "2023-01-01' OR '1'='1", target: "
|
|
11
|
-
oracle: "
|
|
6
|
+
- { id: CHK-SEC-SQLI-01, value: "admin' --", target: "login username", expect: "must NOT log in bypassing the password" }
|
|
7
|
+
- { id: CHK-SEC-SQLI-02, value: "test' OR '1'='1", target: "search box", expect: "must NOT return all rows" }
|
|
8
|
+
- { id: CHK-SEC-SQLI-03, value: "test@test.com' OR '1'='1", target: "signup email", expect: "handled safely, no bad data stored" }
|
|
9
|
+
- { id: CHK-SEC-SQLI-04, value: "test', isAdmin = 1 --", target: "edit profile", expect: "must NOT escalate privileges" }
|
|
10
|
+
- { id: CHK-SEC-SQLI-05, value: "2023-01-01' OR '1'='1", target: "report filter", expect: "returns only the filtered data" }
|
|
11
|
+
oracle: "Any sign of bypass / wrong data returned = a vulnerability. Expected: escape/parametrize safely, return a valid error."
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Security payload bank: Upload file — from common-checklist.xlsx (Upload file function).
|
|
2
2
|
class: upload
|
|
3
|
-
description:
|
|
3
|
+
description: Malicious / constraint-breaking file upload.
|
|
4
4
|
payloads:
|
|
5
|
-
- { id: CHK-SEC-UP-01, technique: "
|
|
6
|
-
- { id: CHK-SEC-UP-02, technique: "MIME mismatch (
|
|
7
|
-
- { id: CHK-SEC-UP-03, technique: "oversize
|
|
8
|
-
- { id: CHK-SEC-UP-04, technique: "path traversal
|
|
9
|
-
- { id: CHK-SEC-UP-05, technique: "
|
|
10
|
-
oracle: "
|
|
5
|
+
- { id: CHK-SEC-UP-01, technique: "extension spoofing (shell.php.jpg)", expect: "checks real MIME + whitelist, rejects" }
|
|
6
|
+
- { id: CHK-SEC-UP-02, technique: "MIME mismatch (altered Content-Type)", expect: "verifies real content" }
|
|
7
|
+
- { id: CHK-SEC-UP-03, technique: "oversize beyond the limit", expect: "reports a size error" }
|
|
8
|
+
- { id: CHK-SEC-UP-04, technique: "path traversal in the filename (../../)", expect: "sanitizes the filename, stores in the right folder" }
|
|
9
|
+
- { id: CHK-SEC-UP-05, technique: "filename containing <script> / malicious metadata", expect: "handled safely, not rendered into the DOM" }
|
|
10
|
+
oracle: "Execution / write outside scope = a vulnerability."
|
package/common/security/xss.yaml
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Security payload bank: XSS Injection — from common-checklist.xlsx (XSS Injection sheet).
|
|
2
2
|
class: xss
|
|
3
|
-
description: Cross-Site Scripting —
|
|
3
|
+
description: Cross-Site Scripting — inject script via input/URL/attribute/file to execute in the page.
|
|
4
4
|
payloads:
|
|
5
|
-
- { id: CHK-SEC-XSS-01, value: "<script>alert('XSS')</script>", kind: "Reflected/Stored", expect: "
|
|
6
|
-
- { id: CHK-SEC-XSS-02, value: "<img src=x onerror=alert(1)>", kind: "HTML attribute", expect: "
|
|
7
|
-
- { id: CHK-SEC-XSS-03, value: "<svg onload=alert(1)>", kind: "SVG payload", expect: "
|
|
8
|
-
- { id: CHK-SEC-XSS-04, value: "\"><script>alert(1)</script>", kind: "Attribute injection", expect: "
|
|
9
|
-
- { id: CHK-SEC-XSS-05, value: "<a href=\"javascript:alert(1)\">click me</a>", kind: "Dangerous link", expect: "href
|
|
10
|
-
- { id: CHK-SEC-XSS-06, value: "<script>alert(1)</script>.jpg", kind: "File name / metadata", expect: "
|
|
11
|
-
- { id: CHK-SEC-XSS-07, value: "<h1>test</h1>", kind: "HTML injection", expect: "
|
|
12
|
-
oracle: "
|
|
5
|
+
- { id: CHK-SEC-XSS-01, value: "<script>alert('XSS')</script>", kind: "Reflected/Stored", expect: "renders as plain text, does NOT execute the script" }
|
|
6
|
+
- { id: CHK-SEC-XSS-02, value: "<img src=x onerror=alert(1)>", kind: "HTML attribute", expect: "does not fire onerror" }
|
|
7
|
+
- { id: CHK-SEC-XSS-03, value: "<svg onload=alert(1)>", kind: "SVG payload", expect: "does not fire onload / strips the attribute" }
|
|
8
|
+
- { id: CHK-SEC-XSS-04, value: "\"><script>alert(1)</script>", kind: "Attribute injection", expect: "does not break the HTML, escapes safely" }
|
|
9
|
+
- { id: CHK-SEC-XSS-05, value: "<a href=\"javascript:alert(1)\">click me</a>", kind: "Dangerous link", expect: "href disabled / sanitized" }
|
|
10
|
+
- { id: CHK-SEC-XSS-06, value: "<script>alert(1)</script>.jpg", kind: "File name / metadata", expect: "filename handled safely, not rendered into the DOM" }
|
|
11
|
+
- { id: CHK-SEC-XSS-07, value: "<h1>test</h1>", kind: "HTML injection", expect: "displayed as text, not rendered as a tag" }
|
|
12
|
+
oracle: "An alert firing / a tag rendering = a vulnerability. Expected: escape/sanitize, no innerHTML/eval on user input."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Technique: Boundary Value Analysis — from
|
|
1
|
+
# Technique: Boundary Value Analysis — from the 4-source method.
|
|
2
2
|
technique: boundary
|
|
3
|
-
description:
|
|
4
|
-
rule: "
|
|
3
|
+
description: When a field has a clear min/max — generate values at and around the boundary.
|
|
4
|
+
rule: "For [min,max]: generate Min-1 (invalid), Min, Min+1, Max-1, Max, Max+1 (invalid)."
|
|
5
5
|
applies_to: [number-integer, number-float, currency, string, password, phone, postcode]
|
|
6
|
-
note: "
|
|
6
|
+
note: "Must include the exact boundary (Min, Max), not only over-boundary — off-by-one usually slips through here."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Technique: Decision Table — from
|
|
1
|
+
# Technique: Decision Table — from the 4-source method.
|
|
2
2
|
technique: decision-table
|
|
3
|
-
description:
|
|
4
|
-
rule: "
|
|
3
|
+
description: Multiple combined conditions affecting one outcome.
|
|
4
|
+
rule: "List condition combinations -> action; generate @cases from each rule row."
|
|
5
5
|
applies_to: [login, permission, business-flow]
|
|
6
|
-
example: "Login:
|
|
6
|
+
example: "Login: password correct/wrong x account locked/unlocked x 2FA on/off."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Technique: Equivalence Partitioning — from
|
|
1
|
+
# Technique: Equivalence Partitioning — from the 4-source method.
|
|
2
2
|
technique: equivalence
|
|
3
|
-
description:
|
|
4
|
-
rule: "
|
|
3
|
+
description: Inputs split into classes with the same behavior — one representative per class is enough.
|
|
4
|
+
rule: "Group values into equivalence classes (valid / each kind of invalid) -> one representative per class, avoid over-testing."
|
|
5
5
|
applies_to: [all]
|
|
6
|
-
note: "
|
|
6
|
+
note: "You don't need 300 bad emails — just one representative per WAY of being wrong (missing @, dot in wrong place, full-width...)."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Technique: State Transition + Dependency State Coverage — from
|
|
1
|
+
# Technique: State Transition + Dependency State Coverage — from the 4-source method.
|
|
2
2
|
technique: state-transition
|
|
3
|
-
description:
|
|
4
|
-
rule: "
|
|
3
|
+
description: An object with multiple states; or A depends on the state of B.
|
|
4
|
+
rule: "Cover valid transitions + INVALID reverse transitions; test X with B in every state (active/inactive/expired/soft-deleted)."
|
|
5
5
|
applies_to: [workflow-entity, dependent-feature]
|
|
6
|
-
example: "Draft
|
|
6
|
+
example: "Draft -> Submitted -> Approved -> Shipped (including invalid reverse transitions)."
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sungen/driver-data-factory",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.12-beta.10",
|
|
4
4
|
"description": "Sungen Data Factory capability — standardized test-data generation from a field-type + security knowledge catalog (valid/boundary/invalid + traceability), the .overwrite merge layer, and (opt-in) @dataFactory runtime seeding. Design-time knowledge is runtime-free. Plugs into @sun-asterisk/sungen via the capability SPI.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
12
|
-
"test": "tsx tests/run.ts"
|
|
12
|
+
"test": "tsx tests/run.ts && tsx tests/golden.ts"
|
|
13
13
|
},
|
|
14
14
|
"author": "eqe team (engineer & quality) — Sun Asterisk",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@sun-asterisk/sungen": "3.2.
|
|
17
|
+
"@sun-asterisk/sungen": "3.2.12-beta.10",
|
|
18
18
|
"yaml": "^2.4.0"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|