@aderis-erp/cli 1.1.3 → 1.1.5
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/README.md +1 -0
- package/dist/commands/access-groups.js +42 -8
- package/dist/commands/account-transaction-allocations.js +38 -4
- package/dist/commands/account-transactions.d.ts +2 -0
- package/dist/commands/account-transactions.js +68 -32
- package/dist/commands/accounts.js +46 -12
- package/dist/commands/agent-platform.js +37 -3
- package/dist/commands/agent-runs.js +49 -15
- package/dist/commands/analytics.js +39 -5
- package/dist/commands/api-clients.d.ts +58 -0
- package/dist/commands/api-clients.js +1375 -0
- package/dist/commands/api-keys.js +40 -6
- package/dist/commands/async-jobs.js +45 -11
- package/dist/commands/audit-log.js +38 -4
- package/dist/commands/bank-accounts.js +54 -20
- package/dist/commands/bank-integrations.js +56 -22
- package/dist/commands/business-partners.js +77 -43
- package/dist/commands/chat.js +43 -9
- package/dist/commands/credit-card-accounts.d.ts +4 -0
- package/dist/commands/credit-card-accounts.js +64 -25
- package/dist/commands/currencies.d.ts +56 -0
- package/dist/commands/currencies.js +1361 -0
- package/dist/commands/custody-accounts.d.ts +56 -0
- package/dist/commands/custody-accounts.js +1369 -0
- package/dist/commands/{integration-identities.d.ts → dashboards.d.ts} +3 -3
- package/dist/commands/dashboards.js +1381 -0
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +57 -0
- package/dist/commands/{integration-identities.js → document-checksums.js} +48 -21
- package/dist/commands/dunning-configs.js +41 -7
- package/dist/commands/dunning-reminders.js +44 -10
- package/dist/commands/dunning-runs.js +37 -3
- package/dist/commands/email-transactions.js +39 -5
- package/dist/commands/employees.js +77 -43
- package/dist/commands/entity-configurations.js +39 -5
- package/dist/commands/event-mapping-rules.js +37 -3
- package/dist/commands/event-processor-mappings.js +41 -7
- package/dist/commands/files.js +48 -14
- package/dist/commands/financial-instrument-transactions.d.ts +56 -0
- package/dist/commands/financial-instrument-transactions.js +1369 -0
- package/dist/commands/financial-instrument-types.d.ts +56 -0
- package/dist/commands/financial-instrument-types.js +1369 -0
- package/dist/commands/financial-instruments.d.ts +56 -0
- package/dist/commands/financial-instruments.js +1369 -0
- package/dist/commands/health.js +41 -7
- package/dist/commands/imports.js +39 -5
- package/dist/commands/inbox.js +42 -8
- package/dist/commands/integrations.js +39 -5
- package/dist/commands/item-categories.js +41 -7
- package/dist/commands/items.js +42 -8
- package/dist/commands/journal-lines.js +37 -3
- package/dist/commands/journals.js +61 -27
- package/dist/commands/{workflows.d.ts → kpis.d.ts} +1 -1
- package/dist/commands/kpis.js +1371 -0
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.d.ts +56 -0
- package/dist/commands/notifications.js +1360 -0
- package/dist/commands/office-locations.js +41 -7
- package/dist/commands/payment-methods.js +46 -12
- package/dist/commands/payment-runs.js +54 -20
- package/dist/commands/payment-terms.js +42 -8
- package/dist/commands/payments.js +43 -9
- package/dist/commands/payroll-runs.js +71 -37
- package/dist/commands/permissions.js +37 -3
- package/dist/commands/price-lists.js +48 -14
- package/dist/commands/processor-mappings.js +40 -6
- package/dist/commands/processors.js +46 -12
- package/dist/commands/purchase-order-types.js +41 -7
- package/dist/commands/purchase-orders.js +60 -26
- package/dist/commands/reports.js +43 -8
- package/dist/commands/roles.js +40 -6
- package/dist/commands/salary-types.js +41 -7
- package/dist/commands/sales-invoices.js +85 -51
- package/dist/commands/sales-orders.js +69 -35
- package/dist/commands/saved-views.js +39 -5
- package/dist/commands/scheduled-processor-mappings.js +41 -7
- package/dist/commands/schedules.js +45 -11
- package/dist/commands/settings.d.ts +56 -0
- package/dist/commands/settings.js +1361 -0
- package/dist/commands/tags.js +42 -8
- package/dist/commands/tax-codes.js +44 -10
- package/dist/commands/tax-matrix.js +41 -7
- package/dist/commands/templates.js +50 -15
- package/dist/commands/tenants.js +44 -10
- package/dist/commands/tools.js +38 -4
- package/dist/commands/users.js +58 -24
- package/dist/commands/vat-declarations.js +61 -27
- package/dist/commands/vendor-invoices.js +82 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.d.ts +56 -0
- package/dist/commands/{workflows.js → work-summary.js} +49 -18
- package/dist/lib/auth/index.js +5 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.d.ts +42 -0
- package/dist/lib/production-guard.js +94 -0
- package/oclif.manifest.json +2142 -333
- package/package.json +9 -3
package/dist/lib/auth/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import { clearSupportSession, getAuthType, getBaseUrls, getContext, getSupportSession, missingCredentialsMessage, saveCachedTenants, saveSupportSession, saveTokens, SESSION_EXPIRED_MESSAGE, unauthorizedMessage, } from '../config.js';
|
|
7
|
+
import { assertProductionAccess } from '../production-guard.js';
|
|
7
8
|
import { AuthError, TenantMismatchError } from './errors.js';
|
|
8
9
|
import { runBrowserFlow } from './flow.js';
|
|
9
10
|
import { requireOAuthContext } from './guards.js';
|
|
@@ -49,6 +50,7 @@ function withTenantAssertion(rounds, tenantId) {
|
|
|
49
50
|
}
|
|
50
51
|
export async function login(context, options = {}) {
|
|
51
52
|
requireOAuthContext(context, 'Browser login');
|
|
53
|
+
assertProductionAccess(context);
|
|
52
54
|
return runBrowserFlow(context, keycloakProvider, [{ prompt: options.prompt }], {
|
|
53
55
|
log: options.log,
|
|
54
56
|
openBrowser: options.openBrowser,
|
|
@@ -99,6 +101,9 @@ export async function getValidToken(contextName) {
|
|
|
99
101
|
*/
|
|
100
102
|
export async function getAuthHeaders(contextName) {
|
|
101
103
|
const context = requireContext(contextName);
|
|
104
|
+
// Every API request fetches its headers here, so production is refused before
|
|
105
|
+
// a token is read or refreshed. `login` guards the minting of live tokens.
|
|
106
|
+
assertProductionAccess(context);
|
|
102
107
|
if (getAuthType(context) === 'api_key') {
|
|
103
108
|
if (!context.api_key) {
|
|
104
109
|
throw new Error(missingCredentialsMessage(context));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expands a leading `~` to the user's home directory.
|
|
3
|
+
*
|
|
4
|
+
* The shell only expands a tilde that starts a word, so `-f ~/log.jsonl`
|
|
5
|
+
* arrives expanded but `--file=~/log.jsonl` reaches us verbatim and would
|
|
6
|
+
* otherwise be looked up as a directory called `~`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveUserPath(input: string): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Expands a leading `~` to the user's home directory.
|
|
5
|
+
*
|
|
6
|
+
* The shell only expands a tilde that starts a word, so `-f ~/log.jsonl`
|
|
7
|
+
* arrives expanded but `--file=~/log.jsonl` reaches us verbatim and would
|
|
8
|
+
* otherwise be looked up as a directory called `~`.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveUserPath(input) {
|
|
11
|
+
if (input === '~')
|
|
12
|
+
return os.homedir();
|
|
13
|
+
if (input.startsWith('~/'))
|
|
14
|
+
return path.join(os.homedir(), input.slice(2));
|
|
15
|
+
return input;
|
|
16
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Context } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* The Claude organisation of Aderis AG. From an aderis.com address, it is the
|
|
4
|
+
* only Claude account that may drive the `live` environment through this CLI.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ADERIS_CLAUDE_ORGANIZATION_UUID = "f5d2d8c1-7256-4628-89d9-45c029577670";
|
|
7
|
+
/** Staff addresses: the guard applies to these and to nobody else. */
|
|
8
|
+
export declare const ADERIS_EMAIL_DOMAIN = "aderis.com";
|
|
9
|
+
/** The Claude Code account that is running this process. */
|
|
10
|
+
export interface ClaudeAccount {
|
|
11
|
+
email?: string;
|
|
12
|
+
organizationUuid?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Thrown when a Claude account outside the Aderis organisation reaches for production. */
|
|
15
|
+
export declare class ProductionAccessError extends Error {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The Claude Code account driving this process, or `null` when no Claude Code
|
|
20
|
+
* session is (`CLAUDECODE` unset): a person at the terminal is not gated.
|
|
21
|
+
*
|
|
22
|
+
* Claude Code exports the account into the environment of every command it
|
|
23
|
+
* runs (`CLAUDE_CODE_USER_EMAIL`, `CLAUDE_CODE_ORGANIZATION_UUID`); whatever the
|
|
24
|
+
* environment lacks is filled in from the stored account file.
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectClaudeAccount(env?: NodeJS.ProcessEnv, homedir?: string): ClaudeAccount | null;
|
|
27
|
+
/** Whether an address belongs to Aderis staff (case-insensitive). */
|
|
28
|
+
export declare function isAderisAddress(email?: string): boolean;
|
|
29
|
+
/** The error shown when production is refused; names the account so the fix is obvious. */
|
|
30
|
+
export declare function productionRefusedMessage(context: Context, account: ClaudeAccount): string;
|
|
31
|
+
/**
|
|
32
|
+
* Refuses production for Aderis staff who drive the CLI from Claude Code with a
|
|
33
|
+
* Claude account outside the Aderis organisation, so no customer data passes
|
|
34
|
+
* through a personal Claude subscription. Fails exactly when all three hold:
|
|
35
|
+
* the context is `live`, the Claude account has an aderis.com address, and its
|
|
36
|
+
* organisation is not {@link ADERIS_CLAUDE_ORGANIZATION_UUID}.
|
|
37
|
+
*
|
|
38
|
+
* Runs before any token is read, refreshed or minted. It is a client-side
|
|
39
|
+
* tripwire against the accidental case, not a security boundary: the API
|
|
40
|
+
* cannot tell which Claude account made a call.
|
|
41
|
+
*/
|
|
42
|
+
export declare function assertProductionAccess(context: Context, account?: ClaudeAccount | null): void;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* The Claude organisation of Aderis AG. From an aderis.com address, it is the
|
|
6
|
+
* only Claude account that may drive the `live` environment through this CLI.
|
|
7
|
+
*/
|
|
8
|
+
export const ADERIS_CLAUDE_ORGANIZATION_UUID = 'f5d2d8c1-7256-4628-89d9-45c029577670';
|
|
9
|
+
/** Staff addresses: the guard applies to these and to nobody else. */
|
|
10
|
+
export const ADERIS_EMAIL_DOMAIN = 'aderis.com';
|
|
11
|
+
/** Thrown when a Claude account outside the Aderis organisation reaches for production. */
|
|
12
|
+
export class ProductionAccessError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'ProductionAccessError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function nonEmpty(value) {
|
|
19
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Claude Code keeps the signed-in account in `.claude.json` under
|
|
23
|
+
* `oauthAccount`, in `$CLAUDE_CONFIG_DIR` or the home directory. Unreadable or
|
|
24
|
+
* malformed means "nothing known", never an error: the file is Claude's, not ours.
|
|
25
|
+
*/
|
|
26
|
+
function readStoredAccount(env, homedir) {
|
|
27
|
+
const dir = env.CLAUDE_CONFIG_DIR ? path.resolve(env.CLAUDE_CONFIG_DIR) : homedir;
|
|
28
|
+
try {
|
|
29
|
+
// The directory is the local user's own CLAUDE_CONFIG_DIR or home, and the file name is fixed.
|
|
30
|
+
// nosemgrep: AIK_ts_generic_path_traversal
|
|
31
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(dir, '.claude.json'), 'utf8'));
|
|
32
|
+
const account = parsed.oauthAccount;
|
|
33
|
+
if (!account || typeof account !== 'object')
|
|
34
|
+
return undefined;
|
|
35
|
+
return { email: nonEmpty(account.emailAddress), organizationUuid: nonEmpty(account.organizationUuid) };
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The Claude Code account driving this process, or `null` when no Claude Code
|
|
43
|
+
* session is (`CLAUDECODE` unset): a person at the terminal is not gated.
|
|
44
|
+
*
|
|
45
|
+
* Claude Code exports the account into the environment of every command it
|
|
46
|
+
* runs (`CLAUDE_CODE_USER_EMAIL`, `CLAUDE_CODE_ORGANIZATION_UUID`); whatever the
|
|
47
|
+
* environment lacks is filled in from the stored account file.
|
|
48
|
+
*/
|
|
49
|
+
export function detectClaudeAccount(env = process.env, homedir = os.homedir()) {
|
|
50
|
+
if (!nonEmpty(env.CLAUDECODE))
|
|
51
|
+
return null;
|
|
52
|
+
const fromEnv = {
|
|
53
|
+
email: nonEmpty(env.CLAUDE_CODE_USER_EMAIL),
|
|
54
|
+
organizationUuid: nonEmpty(env.CLAUDE_CODE_ORGANIZATION_UUID),
|
|
55
|
+
};
|
|
56
|
+
if (fromEnv.email && fromEnv.organizationUuid)
|
|
57
|
+
return fromEnv;
|
|
58
|
+
const stored = readStoredAccount(env, homedir);
|
|
59
|
+
return {
|
|
60
|
+
email: fromEnv.email ?? stored?.email,
|
|
61
|
+
organizationUuid: fromEnv.organizationUuid ?? stored?.organizationUuid,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Whether an address belongs to Aderis staff (case-insensitive). */
|
|
65
|
+
export function isAderisAddress(email) {
|
|
66
|
+
return email?.trim().toLowerCase().endsWith(`@${ADERIS_EMAIL_DOMAIN}`) ?? false;
|
|
67
|
+
}
|
|
68
|
+
/** The error shown when production is refused; names the account so the fix is obvious. */
|
|
69
|
+
export function productionRefusedMessage(context, account) {
|
|
70
|
+
return (`Production access refused for context "${context.name}" (live): Claude Code is signed in as ` +
|
|
71
|
+
`${account.email} in Claude organisation ${account.organizationUuid ?? 'unknown'}, which is not the ` +
|
|
72
|
+
'Aderis organisation. Aderis staff may only reach production through a Claude account in the Aderis ' +
|
|
73
|
+
'organisation. Sign in to Claude Code with your Aderis Team account, or use a non-production context.');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Refuses production for Aderis staff who drive the CLI from Claude Code with a
|
|
77
|
+
* Claude account outside the Aderis organisation, so no customer data passes
|
|
78
|
+
* through a personal Claude subscription. Fails exactly when all three hold:
|
|
79
|
+
* the context is `live`, the Claude account has an aderis.com address, and its
|
|
80
|
+
* organisation is not {@link ADERIS_CLAUDE_ORGANIZATION_UUID}.
|
|
81
|
+
*
|
|
82
|
+
* Runs before any token is read, refreshed or minted. It is a client-side
|
|
83
|
+
* tripwire against the accidental case, not a security boundary: the API
|
|
84
|
+
* cannot tell which Claude account made a call.
|
|
85
|
+
*/
|
|
86
|
+
export function assertProductionAccess(context, account = detectClaudeAccount()) {
|
|
87
|
+
if (context.environment !== 'live')
|
|
88
|
+
return;
|
|
89
|
+
if (!account || !isAderisAddress(account.email))
|
|
90
|
+
return;
|
|
91
|
+
if (account.organizationUuid?.toLowerCase() === ADERIS_CLAUDE_ORGANIZATION_UUID)
|
|
92
|
+
return;
|
|
93
|
+
throw new ProductionAccessError(productionRefusedMessage(context, account));
|
|
94
|
+
}
|