Repository navigation
feat(bansafe): add complete CLI support #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+2,121
−0
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c7ad5e5
feat(bansafe): add complete CLI support
purpshell d50ee53
fix(bansafe): label claim amounts as credit quantities
purpshell 7cf04a4
chore(deps): pin SDK BanSafe head rebased on dev
purpshell 792153a
chore(deps): pin SDK dev at the merged BanSafe change
purpshell b1895fe
docs: record the SDK dev pin after the cloud-launch merge
purpshell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # BanSafe SDK integration check | ||
|
|
||
| The BanSafe CLI commands depend on the matching typed SDK revision pinned in | ||
| `package.json`. During coordinated SDK and CLI development, verify both | ||
| worktrees without replacing that immutable dependency in either manifest: | ||
|
|
||
| The pinned SDK revision is `polymorfa/sdks@8803f0554314214519971cb3306e0c0efe21cb76`. | ||
| Its coverage ledger is reconciled against the API contracts at | ||
| `polymorfa/polymorfa@aca849cda44ad8582d7ae87489404d2483173a53` (Platform | ||
| snapshot SHA-256 | ||
| `2a30e8e0af8902703609f8ed0f5bb2c108b39c5c11863d5ebd8907e56a9f25d2`). | ||
|
|
||
| ```shell | ||
| export POLYMORFA_SDK_CHECKOUT=/absolute/path/to/bansafe-health-sdk | ||
| export POLYMORFA_CLI_CHECKOUT=/absolute/path/to/bansafe-health-cli | ||
|
|
||
| cd "$POLYMORFA_SDK_CHECKOUT" | ||
| npm install --ignore-scripts | ||
| npm run build | ||
| npm run typecheck | ||
| npx vitest run packages/typescript/test/bansafe.test.ts | ||
|
|
||
| cd "$POLYMORFA_CLI_CHECKOUT" | ||
| npm install --ignore-scripts | ||
| npm install --no-save --package-lock=false "$POLYMORFA_SDK_CHECKOUT" | ||
| npm run typecheck | ||
| npx vitest run test/commands/bansafe.test.ts | ||
| npm run build | ||
| ``` | ||
|
|
||
| Before publishing the CLI, confirm that the pinned SDK revision remains | ||
| available, run `npm ci`, and run `npm run verify` from a fresh checkout. A | ||
| local-path install is integration evidence only; it is not a publishable | ||
| dependency. | ||
|
|
||
| The CLI mapping covers all 25 Platform BanSafe operations in the SDK coverage | ||
| ledger. The SDK also covers the 10 equivalent Messaging settings routes through | ||
| `MessagingClient.banSafe`; the CLI uses the Platform routes for those settings | ||
| because BanSafe commands authenticate with an organization server API key. | ||
|
|
||
| | SDK operations | CLI commands | | ||
| | ------------------------------------------------------------ | ---------------------------------------------------------- | | ||
| | `banSafe.listHealth`, `getHealth`, `listHealthHistory` | `bansafe health list`, `view`, `history` | | ||
| | `banSafe.listSignals` | `bansafe signal list` | | ||
| | `banSafe.getTelemetry`, `listTelemetryHistory` | `bansafe telemetry view`, `history` | | ||
| | `banSafe.listCollection` | `bansafe collection list` | | ||
| | `banSafe.listHealthActions` | `bansafe health-action list` | | ||
| | `banSafe.listFindings` | `bansafe finding list` | | ||
| | `banSafe.listEnforcement` | `bansafe enforcement list` | | ||
| | `banSafe.listIncidents`, `createIncident`, `retractIncident` | `bansafe incident list`, `report`, `retract` | | ||
| | `banSafe.listClaims`, `getClaim` | `bansafe claim list`, `view` | | ||
| | `projects.getSafeMode`, `updateSafeMode` | `bansafe safe-mode view`, `update` with `--project` | | ||
| | `sessions.getSafeMode`, `updateSafeMode` | `bansafe safe-mode view`, `update` with a session argument | | ||
| | `projects.getWarmupPlan`, `updateWarmupPlan` | `bansafe warmup view`, `update` | | ||
| | `projects.getHealthPolicy`, `updateHealthPolicy` | `bansafe health-policy view`, `update` | | ||
| | `projects.getInsuranceEvidence`, `updateInsuranceEvidence` | `bansafe insurance-evidence view`, `update` | | ||
|
|
||
| Finding acknowledgement and enforcement appeal are dashboard-identity | ||
| operations. They are intentionally absent from both the server SDK and CLI. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import {Flags} from '@oclif/core' | ||
| import type {BanSafeClaimStatus} from '@polymorfa/sdk' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {listClaims, renderClaims} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeClaimList extends BaseCommand { | ||
| static override description = | ||
| 'List BanSafe attribution claims for one project.' | ||
| static override flags = { | ||
| cursor: Flags.string({description: 'Continue from an opaque page cursor.'}), | ||
| limit: Flags.integer({max: 100, min: 1}), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| session: Flags.string({description: 'Match one session ID or name.'}), | ||
| status: Flags.string({ | ||
| options: [ | ||
| 'filed', | ||
| 'under_review', | ||
| 'approved', | ||
| 'denied', | ||
| 'paid', | ||
| 'reversed', | ||
| ], | ||
| }), | ||
| } | ||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeClaimList) | ||
| const result = await listClaims(await this.platformClient(flags), { | ||
| projectId: flags.project, | ||
| ...(flags.cursor === undefined ? {} : {cursor: flags.cursor}), | ||
| ...(flags.limit === undefined ? {} : {limit: flags.limit}), | ||
| ...(flags.session === undefined ? {} : {session: flags.session}), | ||
| ...(flags.status === undefined | ||
| ? {} | ||
| : {status: flags.status as BanSafeClaimStatus}), | ||
| }) | ||
| this.writeValue(result, renderClaims(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import {Args} from '@oclif/core' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {getClaim, renderClaim} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeClaimView extends BaseCommand { | ||
| static override args = { | ||
| claim: Args.string({description: 'Claim ID.', required: true}), | ||
| } | ||
| static override description = 'View one BanSafe attribution claim.' | ||
| async run(): Promise<void> { | ||
| const {args, flags} = await this.parse(BanSafeClaimView) | ||
| const result = await getClaim(await this.platformClient(flags), args.claim) | ||
| this.writeValue(result, renderClaim(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import {Flags} from '@oclif/core' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {listCollection, renderCollection} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeCollectionList extends BaseCommand { | ||
| static override description = | ||
| 'List BanSafe telemetry collection status for one project.' | ||
|
|
||
| static override flags = { | ||
| cursor: Flags.string({description: 'Continue from an opaque page cursor.'}), | ||
| limit: Flags.integer({ | ||
| description: 'Maximum sessions to return (default 25).', | ||
| max: 100, | ||
| min: 1, | ||
| }), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| } | ||
|
|
||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeCollectionList) | ||
| const result = await listCollection(await this.platformClient(flags), { | ||
| projectId: flags.project, | ||
| ...(flags.cursor === undefined ? {} : {cursor: flags.cursor}), | ||
| ...(flags.limit === undefined ? {} : {limit: flags.limit}), | ||
| }) | ||
| this.writeValue(result, renderCollection(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import {Flags} from '@oclif/core' | ||
| import type {BanSafeEnforcementRung} from '@polymorfa/sdk' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {listEnforcement, renderEnforcement} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeEnforcementList extends BaseCommand { | ||
| static override description = | ||
| 'List recorded BanSafe enforcement for one project.' | ||
| static override flags = { | ||
| cursor: Flags.string({description: 'Continue from an opaque page cursor.'}), | ||
| limit: Flags.integer({max: 100, min: 1}), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| rung: Flags.string({ | ||
| options: ['none', 'notify', 'throttle', 'block_cold', 'suspend'], | ||
| }), | ||
| } | ||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeEnforcementList) | ||
| const result = await listEnforcement(await this.platformClient(flags), { | ||
| projectId: flags.project, | ||
| ...(flags.cursor === undefined ? {} : {cursor: flags.cursor}), | ||
| ...(flags.limit === undefined ? {} : {limit: flags.limit}), | ||
| ...(flags.rung === undefined | ||
| ? {} | ||
| : {rung: flags.rung as BanSafeEnforcementRung}), | ||
| }) | ||
| this.writeValue(result, renderEnforcement(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import {Flags} from '@oclif/core' | ||
| import type {BanSafeFindingSeverity, BanSafeFindingStatus} from '@polymorfa/sdk' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {listFindings, renderFindings} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeFindingList extends BaseCommand { | ||
| static override description = | ||
| 'List measured BanSafe findings for one project.' | ||
| static override flags = { | ||
| cursor: Flags.string({description: 'Continue from an opaque page cursor.'}), | ||
| limit: Flags.integer({max: 100, min: 1}), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| session: Flags.string({description: 'Match one session ID or name.'}), | ||
| severity: Flags.string({options: ['info', 'warning', 'critical']}), | ||
| status: Flags.string({options: ['open', 'acknowledged', 'resolved']}), | ||
| } | ||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeFindingList) | ||
| const result = await listFindings(await this.platformClient(flags), { | ||
| projectId: flags.project, | ||
| ...(flags.cursor === undefined ? {} : {cursor: flags.cursor}), | ||
| ...(flags.limit === undefined ? {} : {limit: flags.limit}), | ||
| ...(flags.session === undefined ? {} : {session: flags.session}), | ||
| ...(flags.severity === undefined | ||
| ? {} | ||
| : {severity: flags.severity as BanSafeFindingSeverity}), | ||
| ...(flags.status === undefined | ||
| ? {} | ||
| : { | ||
| status: flags.status as Exclude< | ||
| BanSafeFindingStatus, | ||
| 'not_measured' | ||
| >, | ||
| }), | ||
| }) | ||
| this.writeValue(result, renderFindings(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import {Flags} from '@oclif/core' | ||
| import type {BanSafeHealthActionStatus} from '@polymorfa/sdk' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import { | ||
| listHealthActions, | ||
| renderHealthActions, | ||
| } from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeHealthActionList extends BaseCommand { | ||
| static override description = | ||
| 'List durable BanSafe Health actions for one project.' | ||
|
|
||
| static override flags = { | ||
| cursor: Flags.string({description: 'Continue from an opaque page cursor.'}), | ||
| limit: Flags.integer({ | ||
| description: 'Maximum actions to return (default 25).', | ||
| max: 100, | ||
| min: 1, | ||
| }), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| session: Flags.string({description: 'Match one session ID or name.'}), | ||
| status: Flags.string({ | ||
| description: 'Match one action status.', | ||
| options: ['pending', 'running', 'succeeded', 'failed', 'cancelled'], | ||
| }), | ||
| } | ||
|
|
||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeHealthActionList) | ||
| const result = await listHealthActions(await this.platformClient(flags), { | ||
| projectId: flags.project, | ||
| ...(flags.cursor === undefined ? {} : {cursor: flags.cursor}), | ||
| ...(flags.limit === undefined ? {} : {limit: flags.limit}), | ||
| ...(flags.session === undefined ? {} : {session: flags.session}), | ||
| ...(flags.status === undefined | ||
| ? {} | ||
| : {status: flags.status as BanSafeHealthActionStatus}), | ||
| }) | ||
| this.writeValue(result, renderHealthActions(result.data), flags) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import {Flags} from '@oclif/core' | ||
|
|
||
| import {readJsonInput} from '../../../api/request.js' | ||
| import {BaseCommand} from '../../../base-command.js' | ||
| import { | ||
| renderHealthPolicy, | ||
| updateHealthPolicy, | ||
| } from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeHealthPolicyUpdate extends BaseCommand { | ||
| static override description = | ||
| 'Replace the BanSafe Health rule for one project.' | ||
| static override flags = { | ||
| 'idempotency-key': Flags.string({ | ||
| description: 'Identify retries of this convergent policy update.', | ||
| required: true, | ||
| }), | ||
|
purpshell marked this conversation as resolved.
Resolved
|
||
| input: Flags.string({ | ||
| description: | ||
| 'Read the complete policy JSON object from a file or standard input (-).', | ||
| required: true, | ||
| }), | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| } | ||
|
|
||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeHealthPolicyUpdate) | ||
| const result = await updateHealthPolicy( | ||
| await this.platformClient(flags), | ||
| flags.project, | ||
| await readJsonInput(flags.input), | ||
| {idempotencyKey: flags['idempotency-key']}, | ||
| ) | ||
| this.writeValue(result, renderHealthPolicy(result.data), flags) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import {Flags} from '@oclif/core' | ||
|
|
||
| import {BaseCommand} from '../../../base-command.js' | ||
| import {getHealthPolicy, renderHealthPolicy} from '../../../services/bansafe.js' | ||
|
|
||
| export default class BanSafeHealthPolicyView extends BaseCommand { | ||
| static override description = 'View the BanSafe Health rule for one project.' | ||
| static override flags = { | ||
| project: Flags.string({description: 'Project ID.', required: true}), | ||
| } | ||
|
|
||
| async run(): Promise<void> { | ||
| const {flags} = await this.parse(BanSafeHealthPolicyView) | ||
| const result = await getHealthPolicy( | ||
| await this.platformClient(flags), | ||
| flags.project, | ||
| ) | ||
| this.writeValue(result, renderHealthPolicy(result.data), flags) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.