@secureport/sdk 0.5.0

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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/client.d.ts +135 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +191 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/errors.d.ts +80 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +118 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/index.d.ts +31 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +10 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/pagination.d.ts +27 -0
  16. package/dist/pagination.d.ts.map +1 -0
  17. package/dist/pagination.js +19 -0
  18. package/dist/pagination.js.map +1 -0
  19. package/dist/resources/branding.d.ts +49 -0
  20. package/dist/resources/branding.d.ts.map +1 -0
  21. package/dist/resources/branding.js +38 -0
  22. package/dist/resources/branding.js.map +1 -0
  23. package/dist/resources/issues.d.ts +248 -0
  24. package/dist/resources/issues.d.ts.map +1 -0
  25. package/dist/resources/issues.js +100 -0
  26. package/dist/resources/issues.js.map +1 -0
  27. package/dist/resources/reports.d.ts +83 -0
  28. package/dist/resources/reports.d.ts.map +1 -0
  29. package/dist/resources/reports.js +50 -0
  30. package/dist/resources/reports.js.map +1 -0
  31. package/dist/resources/runs.d.ts +474 -0
  32. package/dist/resources/runs.d.ts.map +1 -0
  33. package/dist/resources/runs.js +281 -0
  34. package/dist/resources/runs.js.map +1 -0
  35. package/dist/resources/suppression-rules.d.ts +43 -0
  36. package/dist/resources/suppression-rules.d.ts.map +1 -0
  37. package/dist/resources/suppression-rules.js +33 -0
  38. package/dist/resources/suppression-rules.js.map +1 -0
  39. package/dist/resources/targets.d.ts +126 -0
  40. package/dist/resources/targets.d.ts.map +1 -0
  41. package/dist/resources/targets.js +83 -0
  42. package/dist/resources/targets.js.map +1 -0
  43. package/package.json +55 -0
  44. package/src/client.ts +328 -0
  45. package/src/errors.ts +120 -0
  46. package/src/index.ts +100 -0
  47. package/src/pagination.ts +41 -0
  48. package/src/resources/branding.ts +59 -0
  49. package/src/resources/issues.ts +344 -0
  50. package/src/resources/reports.ts +104 -0
  51. package/src/resources/runs.ts +635 -0
  52. package/src/resources/suppression-rules.ts +69 -0
  53. package/src/resources/targets.ts +179 -0
@@ -0,0 +1,69 @@
1
+ // The SDK's suppression-rules resource: list, create, get and delete.
2
+ import type { Requester } from '../client.js';
3
+ import type { Page, PageQuery } from '../pagination.js';
4
+ import { paginate } from '../pagination.js';
5
+
6
+ /**
7
+ * A pre-emptive suppression rule. `createdAt` is an ISO 8601 string, as the
8
+ * API sends it — parse it yourself if you need a `Date`.
9
+ */
10
+ export interface SuppressionRule {
11
+ readonly id: string;
12
+ readonly orgId: string;
13
+
14
+ /** `null` means the rule covers every target in the organisation. */
15
+ readonly targetId: string | null;
16
+
17
+ /** Matched against an issue's vulnerability key; `*` is the only wildcard. */
18
+ readonly vulnKeyGlob: string;
19
+ readonly reason: string;
20
+
21
+ /** The authenticated actor that created it — never supplied by the caller. */
22
+ readonly createdBy: string;
23
+ readonly createdAt: string;
24
+ }
25
+
26
+ export type SuppressionRulePage = Page<SuppressionRule>;
27
+
28
+ export interface NewSuppressionRule {
29
+ /** Omit to cover the whole organisation. */
30
+ readonly targetId?: string;
31
+
32
+ /** Anchored at both ends, so `xss-*` does not match `not-xss-reflected`. */
33
+ readonly vulnKeyGlob: string;
34
+ readonly reason: string;
35
+ }
36
+
37
+ /**
38
+ * Pre-emptive "never open an issue for this class" rules — the blunt
39
+ * instrument; per-issue ignore is the default. No update: delete and recreate.
40
+ */
41
+ export class SuppressionRulesResource {
42
+ constructor(private readonly request: Requester) {}
43
+
44
+ list(query?: PageQuery): Promise<SuppressionRulePage> {
45
+ return this.request({ method: 'GET', path: '/suppression-rules', query: { ...query } });
46
+ }
47
+
48
+ /** Every rule, across every page, as an async iterator. */
49
+ listAll(): AsyncIterable<SuppressionRule> {
50
+ return paginate((page) => this.list({ page }));
51
+ }
52
+
53
+ /** @throws {SecureportError} `not_found` if `targetId` names no target of yours. */
54
+ create(input: NewSuppressionRule): Promise<SuppressionRule> {
55
+ return this.request({ method: 'POST', path: '/suppression-rules', body: input });
56
+ }
57
+
58
+ get(id: string): Promise<SuppressionRule> {
59
+ return this.request({ method: 'GET', path: `/suppression-rules/${encodeURIComponent(id)}` });
60
+ }
61
+
62
+ /** Issues the rule already caused to open as ignored stay ignored. */
63
+ delete(id: string): Promise<void> {
64
+ return this.request({
65
+ method: 'DELETE',
66
+ path: `/suppression-rules/${encodeURIComponent(id)}`,
67
+ });
68
+ }
69
+ }
@@ -0,0 +1,179 @@
1
+ import type { Requester } from '../client.js';
2
+ import type { Page, PageQuery } from '../pagination.js';
3
+ import { paginate } from '../pagination.js';
4
+
5
+ /** A target: one thing runs are executed against. */
6
+ export interface Target {
7
+ readonly id: string;
8
+ readonly orgId: string;
9
+
10
+ /** As it appears on a report cover. */
11
+ readonly name: string;
12
+
13
+ /** A URL, host or repository. */
14
+ readonly url: string;
15
+ }
16
+
17
+ export type TargetPage = Page<Target>;
18
+
19
+ export interface NewTarget {
20
+ readonly name: string;
21
+ readonly url: string;
22
+ }
23
+
24
+ /**
25
+ * At least one of `name`/`url` is required — the API answers `{}` with a
26
+ * `422 validation`, not a no-op.
27
+ */
28
+ export interface TargetPatch {
29
+ readonly name?: string;
30
+ readonly url?: string;
31
+ }
32
+
33
+ export type VerificationMethod = 'dns_txt' | 'http_file';
34
+ export type VerificationState = 'unverified' | 'verified';
35
+
36
+ /**
37
+ * The target's current verification state. Never carries the token — see
38
+ * {@link IssuedTargetVerification}, the one response that does.
39
+ *
40
+ * Date fields are ISO 8601 strings, as the API sends them — this type is
41
+ * SDK-local (no `@secureport/core` equivalent exists), so there is no
42
+ * shared revival logic to lean on; parse them yourself if you need `Date`.
43
+ */
44
+ export interface TargetVerification {
45
+ readonly method: VerificationMethod | null;
46
+ readonly state: VerificationState;
47
+ readonly issuedAt: string | null;
48
+
49
+ /** Set only while a rotated token's grace period is still active. */
50
+ readonly previousExpiresAt: string | null;
51
+ }
52
+
53
+ export interface NewTargetVerification {
54
+ readonly method: VerificationMethod;
55
+ }
56
+
57
+ /**
58
+ * The response to issuing (or rotating) a verification token.
59
+ *
60
+ * **The token appears here and nowhere else** — {@link TargetVerification}
61
+ * never carries it, and there is no recovery endpoint. Losing it means
62
+ * issuing a new one, which may reset `state` to `unverified` (see
63
+ * {@link TargetsResource.issueVerification}).
64
+ *
65
+ * `recordName`/`recordValue` are present for `method: 'dns_txt'`;
66
+ * `filePath`/`fileContents` for `method: 'http_file'` — a discriminated
67
+ * pair the wire schema does not enforce, so narrow on `method` yourself.
68
+ */
69
+ export interface IssuedTargetVerification extends Omit<TargetVerification, 'method'> {
70
+ readonly method: VerificationMethod;
71
+ readonly token: string;
72
+ readonly summary: string;
73
+ readonly recordName?: string;
74
+ readonly recordValue?: string;
75
+ readonly filePath?: string;
76
+ readonly fileContents?: string;
77
+ }
78
+
79
+ /** The result of one verification check — evidence, not a status flag. */
80
+ export interface TargetVerificationCheckResult {
81
+ /** This check's own evidence row id — a fresh one every call, whether it passed or failed. */
82
+ readonly id: string;
83
+ readonly verified: boolean;
84
+ readonly state: VerificationState;
85
+ readonly method: VerificationMethod;
86
+ readonly checkedAt: string;
87
+ readonly expected: string;
88
+ readonly observed: string | null;
89
+ readonly message: string;
90
+ }
91
+
92
+ /**
93
+ * Targets, and the per-target verification flow a hosted scan (`kind:
94
+ * 'scan'`) requires before it can start — see `POST /runs`'s
95
+ * `verification_required` gate.
96
+ */
97
+ export class TargetsResource {
98
+ constructor(private readonly request: Requester) {}
99
+
100
+ list(query?: PageQuery): Promise<TargetPage> {
101
+ return this.request({ method: 'GET', path: '/targets', query: { ...query } });
102
+ }
103
+
104
+ /** Every target, across every page, as an async iterator. */
105
+ listAll(): AsyncIterable<Target> {
106
+ return paginate((page) => this.list({ page }));
107
+ }
108
+
109
+ create(input: NewTarget): Promise<Target> {
110
+ return this.request({ method: 'POST', path: '/targets', body: input });
111
+ }
112
+
113
+ get(id: string): Promise<Target> {
114
+ return this.request({ method: 'GET', path: `/targets/${encodeURIComponent(id)}` });
115
+ }
116
+
117
+ /**
118
+ * **Changing `url` silently un-verifies the target** — the stored
119
+ * verification named the old host, and the API drops `state` to
120
+ * `unverified` as part of this same call. A caller relying on the target
121
+ * staying verified across a URL change needs to re-verify afterwards.
122
+ */
123
+ update(id: string, patch: TargetPatch): Promise<Target> {
124
+ return this.request({
125
+ method: 'PATCH',
126
+ path: `/targets/${encodeURIComponent(id)}`,
127
+ body: patch,
128
+ });
129
+ }
130
+
131
+ /** @throws {SecureportError} `conflict` if the target has run or issue history. */
132
+ delete(id: string): Promise<void> {
133
+ return this.request({ method: 'DELETE', path: `/targets/${encodeURIComponent(id)}` });
134
+ }
135
+
136
+ getVerification(id: string): Promise<TargetVerification> {
137
+ return this.request({ method: 'GET', path: `/targets/${encodeURIComponent(id)}/verification` });
138
+ }
139
+
140
+ /**
141
+ * Issues a fresh verification token, or rotates the current one — decided
142
+ * server-side, not by this method: calling with the **same `method`** as
143
+ * an already-verified target **rotates** (the target stays `verified`,
144
+ * and the old token keeps working for a 24-hour grace period). Calling
145
+ * with any other method, or while unverified, **re-issues** and resets
146
+ * `state` to `unverified` until the new token is checked.
147
+ */
148
+ issueVerification(id: string, input: NewTargetVerification): Promise<IssuedTargetVerification> {
149
+ return this.request({
150
+ method: 'POST',
151
+ path: `/targets/${encodeURIComponent(id)}/verification`,
152
+ body: input,
153
+ });
154
+ }
155
+
156
+ /**
157
+ * Runs the verification check now, fresh — never trusts a stored flag.
158
+ * **Promote-only**: a match sets `state: 'verified'`; a mismatch or
159
+ * unreachable record is recorded as evidence but never demotes a target
160
+ * that is already verified. Writes a new evidence row every call, whether
161
+ * it passes or fails — not a no-op check.
162
+ *
163
+ * @throws {SecureportError} `conflict` if no token has been issued yet.
164
+ */
165
+ verify(id: string): Promise<TargetVerificationCheckResult> {
166
+ return this.request({ method: 'POST', path: `/targets/${encodeURIComponent(id)}/verify` });
167
+ }
168
+
169
+ /**
170
+ * Revokes the current token outright — idempotent; revoking an
171
+ * already-unverified target is a clean no-op, not an error.
172
+ */
173
+ revokeVerification(id: string): Promise<void> {
174
+ return this.request({
175
+ method: 'DELETE',
176
+ path: `/targets/${encodeURIComponent(id)}/verification`,
177
+ });
178
+ }
179
+ }