@dreamor/atlas-cli 0.7.23 → 0.7.24

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 (47) hide show
  1. package/README.github.md +230 -0
  2. package/README.md +1 -59
  3. package/atlas.cjs +226 -0
  4. package/package.json +7 -9
  5. package/atlas.js +0 -5
  6. package/dist/adapters/atlas/auth/browser.js +0 -37
  7. package/dist/adapters/atlas/auth/index.js +0 -4
  8. package/dist/adapters/atlas/auth/login.js +0 -187
  9. package/dist/adapters/atlas/auth/portable.js +0 -193
  10. package/dist/adapters/atlas/auth/refresh.js +0 -138
  11. package/dist/adapters/atlas/auth/session.js +0 -167
  12. package/dist/adapters/atlas/cli.js +0 -561
  13. package/dist/adapters/atlas/commands/_output_schema.js +0 -379
  14. package/dist/adapters/atlas/commands/actual/_logic.js +0 -116
  15. package/dist/adapters/atlas/commands/actual/index.js +0 -138
  16. package/dist/adapters/atlas/commands/auth.js +0 -1
  17. package/dist/adapters/atlas/commands/baseline/index.js +0 -137
  18. package/dist/adapters/atlas/commands/compare/_logic.js +0 -39
  19. package/dist/adapters/atlas/commands/compare/index.js +0 -89
  20. package/dist/adapters/atlas/commands/exec.js +0 -81
  21. package/dist/adapters/atlas/commands/project/index.js +0 -218
  22. package/dist/adapters/atlas/commands/schema.js +0 -25
  23. package/dist/adapters/atlas/commands/suggest.js +0 -83
  24. package/dist/adapters/atlas/commands/update.js +0 -104
  25. package/dist/adapters/atlas/daemon/index.js +0 -145
  26. package/dist/adapters/atlas/dict/index.js +0 -41
  27. package/dist/adapters/atlas/http/client.js +0 -200
  28. package/dist/adapters/atlas/http/index.js +0 -1
  29. package/dist/adapters/atlas/schema/actual.js +0 -16
  30. package/dist/adapters/atlas/schema/baseline.js +0 -34
  31. package/dist/adapters/atlas/schema/department.js +0 -11
  32. package/dist/adapters/atlas/schema/index.js +0 -4
  33. package/dist/adapters/atlas/schema/project.js +0 -13
  34. package/dist/adapters/atlas/util/cidr.js +0 -114
  35. package/dist/adapters/atlas/util/constants.js +0 -4
  36. package/dist/adapters/atlas/util/env.js +0 -56
  37. package/dist/adapters/atlas/util/environment.js +0 -152
  38. package/dist/adapters/atlas/util/errors.js +0 -49
  39. package/dist/adapters/atlas/util/helpers.js +0 -17
  40. package/dist/adapters/atlas/util/months.js +0 -65
  41. package/dist/adapters/atlas/util/output-limit.js +0 -21
  42. package/dist/adapters/atlas/util/output.js +0 -70
  43. package/dist/adapters/atlas/util/paths.js +0 -40
  44. package/dist/adapters/atlas/util/portable-store.js +0 -153
  45. package/dist/adapters/atlas/util/secure-fs.js +0 -41
  46. package/dist/adapters/atlas/util/time.js +0 -17
  47. package/dist/adapters/atlas/util/version.js +0 -1
@@ -1,153 +0,0 @@
1
- /**
2
- * 便携登录态 bundle(对齐 dws portableAuthBundleManifest)。
3
- *
4
- * bundle 结构(gzip + JSON 明文,复用 cookies 已明文的事实):
5
- *
6
- * atlas-auth.tar.gz(实际是 gzip(JSON) 单文件,非真 tar — 简化实现)
7
- * └── { manifest: {...}, cookies: [...] }
8
- *
9
- * base64 模式 = base64(gzip(JSON)),方便通过 env / 管道传输。
10
- *
11
- * 安全:--refresh-only 默认开启,剥离短命 token(access_token* / refresh_token*),
12
- * 只保留 SSO_REFRESH_TOKEN + buc_* + 身份相关 cookies。导出文件权限 0600
13
- * (secureWriteFile)。
14
- *
15
- * 零运行时依赖:仅用 node:zlib + secure-fs。
16
- */
17
- import { gzip, gunzip } from 'zlib';
18
- import { promisify } from 'util';
19
- import { readFile, mkdir } from 'fs/promises';
20
- import { dirname, resolve } from 'path';
21
- import { existsSync } from 'fs';
22
- import { secureWriteFile } from './secure-fs.js';
23
- import { ConfigError } from './errors.js';
24
- import { platform } from 'os';
25
- const gzipAsync = promisify(gzip);
26
- const gunzipAsync = promisify(gunzip);
27
- export const BUNDLE_SCHEMA = 'atlas.auth.bundle/v1';
28
- export const BUNDLE_VERSION = 1;
29
- /** 短命 token cookie 名集合(--refresh-only 时剥离) */
30
- const EPHEMERAL_TOKEN_NAMES = new Set([
31
- 'access_token',
32
- 'access_token.sig',
33
- 'refresh_token',
34
- 'refresh_token.sig',
35
- ]);
36
- /** 构造 bundle(纯函数) */
37
- export function buildBundle(cookies, opts) {
38
- const filtered = opts.refreshOnly === false
39
- ? cookies
40
- : cookies.filter((c) => !EPHEMERAL_TOKEN_NAMES.has(c.name));
41
- return {
42
- manifest: {
43
- schema: BUNDLE_SCHEMA,
44
- version: BUNDLE_VERSION,
45
- os: opts.os ?? platform(),
46
- exportedAt: opts.exportedAt,
47
- refreshOnly: opts.refreshOnly,
48
- },
49
- cookies: filtered,
50
- };
51
- }
52
- /** 序列化为 gzip + base64 字符串(适合 --base64 stdout) */
53
- export async function serializeBundleBase64(bundle) {
54
- const json = JSON.stringify(bundle);
55
- const zipped = await gzipAsync(Buffer.from(json, 'utf-8'));
56
- return zipped.toString('base64');
57
- }
58
- /** 序列化为 gzip Buffer(适合写文件) */
59
- export async function serializeBundleBuffer(bundle) {
60
- const json = JSON.stringify(bundle);
61
- return gzipAsync(Buffer.from(json, 'utf-8'));
62
- }
63
- /** 校验 manifest schema/version,失败抛 ConfigError */
64
- function assertManifest(m) {
65
- if (!m || typeof m !== 'object') {
66
- throw new ConfigError('无效 bundle:manifest 缺失');
67
- }
68
- const o = m;
69
- if (o.schema !== BUNDLE_SCHEMA) {
70
- throw new ConfigError(`无效 bundle:schema 不匹配(期望 ${BUNDLE_SCHEMA},实际 ${String(o.schema)})`);
71
- }
72
- if (typeof o.version !== 'number' || o.version > BUNDLE_VERSION) {
73
- throw new ConfigError(`无效 bundle:版本不支持(当前 ${BUNDLE_VERSION},bundle ${String(o.version)})`);
74
- }
75
- if (!Array.isArray(o.cookies) === false && !o.cookies === undefined) {
76
- // bundles with cookies at top handled below; manifest-only ok
77
- }
78
- }
79
- /** 解析 base64 字符串 → AuthBundle */
80
- export async function parseBundleBase64(b64) {
81
- const buf = Buffer.from(b64.trim(), 'base64');
82
- let json;
83
- try {
84
- json = (await gunzipAsync(buf)).toString('utf-8');
85
- }
86
- catch {
87
- // 兼容未压缩的纯 base64 JSON(少数手动构造场景)
88
- try {
89
- json = buf.toString('utf-8');
90
- }
91
- catch {
92
- throw new ConfigError('无效 bundle:base64 解码失败');
93
- }
94
- }
95
- return parseBundleJson(json);
96
- }
97
- /** 解析文件(gzip 二进制 或 base64 文本)→ AuthBundle */
98
- export async function parseBundleFile(path) {
99
- if (!existsSync(path)) {
100
- throw new ConfigError(`导入文件不存在:${path}`);
101
- }
102
- const raw = await readFile(path);
103
- // 二进制 gzip 文件(前两字节 0x1f 0x8b)
104
- if (raw.length >= 2 && raw[0] === 0x1f && raw[1] === 0x8b) {
105
- const json = (await gunzipAsync(raw)).toString('utf-8');
106
- return parseBundleJson(json);
107
- }
108
- // 否则按 base64 文本处理
109
- return parseBundleBase64(raw.toString('utf-8'));
110
- }
111
- function parseBundleJson(json) {
112
- let obj;
113
- try {
114
- obj = JSON.parse(json);
115
- }
116
- catch {
117
- throw new ConfigError('无效 bundle:JSON 解析失败');
118
- }
119
- if (!obj || typeof obj !== 'object') {
120
- throw new ConfigError('无效 bundle:根节点非对象');
121
- }
122
- const o = obj;
123
- assertManifest(o.manifest);
124
- if (!Array.isArray(o.cookies)) {
125
- throw new ConfigError('无效 bundle:cookies 字段非数组');
126
- }
127
- const bundle = {
128
- manifest: o.manifest,
129
- cookies: o.cookies,
130
- };
131
- const currentOs = platform();
132
- return {
133
- bundle,
134
- warning: {
135
- osMismatch: bundle.manifest.os !== currentOs,
136
- refreshOnly: bundle.manifest.refreshOnly,
137
- },
138
- };
139
- }
140
- /**
141
- * 写 bundle 到文件路径(secureWriteFile 0600)。
142
- *
143
- * 与 baseline/actual export 的 --out 白名单(resolveSecureExportPath)不同:
144
- * auth export 输出的是便携凭证 bundle,用户主动指定任意路径(如 /tmp 方便传输
145
- * 到沙盒)是其核心用例,因此放宽为绝对/相对路径均可,但仍以 0600 写入。
146
- */
147
- export async function writeBundleToFile(bundle, outPath, base64) {
148
- const resolved = resolve(process.cwd(), outPath);
149
- const content = base64 ? await serializeBundleBase64(bundle) : await serializeBundleBuffer(bundle);
150
- await mkdir(dirname(resolved), { recursive: true });
151
- await secureWriteFile(resolved, content);
152
- return resolved;
153
- }
@@ -1,41 +0,0 @@
1
- /**
2
- * 安全文件系统工具。
3
- *
4
- * 统一按最小权限原则读写敏感文件:
5
- * - 目录:0700(drwx------)
6
- * - 文件:0600(-rw-------)
7
- *
8
- * 覆盖已有文件时额外 chmod 兜底。
9
- */
10
- import { mkdir, writeFile, chmod } from 'fs/promises';
11
- import { resolve } from 'path';
12
- import { ConfigError } from './errors.js';
13
- /** 安全的目录创建:0700 */
14
- export async function secureMkdir(dir, opts) {
15
- await mkdir(dir, { recursive: opts?.recursive ?? true, mode: 0o700 });
16
- }
17
- /** 安全的文件写入:0600,覆盖已有 ✓ */
18
- export async function secureWriteFile(file, data) {
19
- await writeFile(file, data, { mode: 0o600 });
20
- await chmod(file, 0o600);
21
- }
22
- /**
23
- * 校验导出路径,防止 --out 任意写(H2 修复)。
24
- *
25
- * 策略:
26
- * - 相对路径:解析为 `{cwd}/{path}`,允许
27
- * - 绝对路径:必须在 `cwd` 目录树内
28
- *
29
- * @param cwdOverride 仅在测试中用于 mock 工作目录
30
- * 返回解析后的绝对路径(可安全传入 writeFile)。
31
- * 校验不通过时抛 ConfigError。
32
- */
33
- export function resolveSecureExportPath(out, cwdOverride) {
34
- const currentDir = cwdOverride ?? process.cwd();
35
- const resolved = resolve(currentDir, out);
36
- if (!resolved.startsWith(currentDir)) {
37
- throw new ConfigError(`--out 路径 "${resolved}" 不在当前工作目录 "${currentDir}" 内,已拒绝。` +
38
- `请将导出文件放在当前目录或子目录中。`);
39
- }
40
- return resolved;
41
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * 时间工具:处理 CST(UTC+8)时区相关的转换。
3
- *
4
- * API 返回的时间戳是中国标准时间(UTC+8)的午夜,
5
- * 必须加 8h 偏移后取 UTC 年月,否则在非 UTC+8 的机器上月份偏 1。
6
- */
7
- /** API 时间戳 → YYYY-MM 月份键,CST 时区安全 */
8
- export function monthTsToKey(ts) {
9
- const d = new Date(ts + 8 * 3600 * 1000);
10
- return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
11
- }
12
- /** 当前月的 YYYY-MM 键 */
13
- export function currentMonthKey() {
14
- const d = new Date();
15
- // 使用本地时间,不偏移;当前月即本地年月
16
- return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
17
- }
@@ -1 +0,0 @@
1
- export const ATLAS_VERSION = '0.7.23';