multi-gws 0.0.1
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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/account-add.d.ts +9 -0
- package/dist/account-add.d.ts.map +1 -0
- package/dist/account-add.js +110 -0
- package/dist/account-add.js.map +1 -0
- package/dist/account-permissions.d.ts +9 -0
- package/dist/account-permissions.d.ts.map +1 -0
- package/dist/account-permissions.js +25 -0
- package/dist/account-permissions.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +93 -0
- package/dist/cli.js.map +1 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/gws-command-policy.d.ts +11 -0
- package/dist/gws-command-policy.d.ts.map +1 -0
- package/dist/gws-command-policy.js +97 -0
- package/dist/gws-command-policy.js.map +1 -0
- package/dist/run.d.ts +9 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +138 -0
- package/dist/run.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mgws contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# multi-gws
|
|
2
|
+
|
|
3
|
+
`multi-gws` provides the `mgws` command, a multi-account safety wrapper for the [Google Workspace CLI](https://github.com/googleworkspace/cli). It selects repository-local account credentials, blocks permanent deletion, and requires confirmation for consequential operations while forwarding the rest of the `gws` command surface.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 22.9 or newer
|
|
8
|
+
- npm 11
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
Run a Google Workspace command with a connected account:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
mgws run <account-slug> <gws arguments...>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Add or reconnect an account:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
mgws account add <email-address> --gmail=<none|read|manage> --drive=<none|read|manage>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`mgws` treats the current working directory as the workspace. Shared OAuth configuration belongs at `credentials/google-oauth-client.json`; account state is stored under `accounts/<account-slug>/gws/`.
|
|
25
|
+
|
|
26
|
+
## Development
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install
|
|
30
|
+
npm run check
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The package uses TypeScript 7, Vitest, and Biome. Commander provides the CLI structure while `mgws run` preserves trailing `gws` arguments for forwarding.
|
|
34
|
+
|
|
35
|
+
## Releasing
|
|
36
|
+
|
|
37
|
+
Maintainers can run `npm run release` from a clean `main` branch. The command
|
|
38
|
+
publishes the current version when it is not on npm yet; subsequent runs bump
|
|
39
|
+
the patch version. Use `npm run release -- minor` or `npm run release -- major`
|
|
40
|
+
to select a larger version bump. The workflow verifies the package, creates and
|
|
41
|
+
pushes the Git tag, and publishes to npm using the current npm credentials.
|
|
42
|
+
|
|
43
|
+
When npm requires a one-time password, provide the current code for that release:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
NPM_CONFIG_OTP=<code> npm run release
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
MIT
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AccountAccess } from "./account-permissions.js";
|
|
2
|
+
export interface AddAccountOptions extends AccountAccess {
|
|
3
|
+
email: string;
|
|
4
|
+
login: boolean;
|
|
5
|
+
workspaceRoot?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function accountSlug(email: string): string;
|
|
8
|
+
export declare function addAccount({ email, gmail, drive, login, workspaceRoot, }: AddAccountOptions): number;
|
|
9
|
+
//# sourceMappingURL=account-add.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-add.d.ts","sourceRoot":"","sources":["../src/account-add.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAqBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBjD;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,aAAa,GACd,EAAE,iBAAiB,GAAG,MAAM,CAmG5B"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { chmodSync, copyFileSync, lstatSync, mkdirSync, writeFileSync, } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { resolveAccountScopes } from "./account-permissions.js";
|
|
6
|
+
import { CliError, EXIT, errorCode } from "./errors.js";
|
|
7
|
+
function isFile(path) {
|
|
8
|
+
try {
|
|
9
|
+
return lstatSync(path).isFile();
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (errorCode(error) === "ENOENT")
|
|
13
|
+
return false;
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function pathExists(path) {
|
|
18
|
+
try {
|
|
19
|
+
lstatSync(path);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (errorCode(error) === "ENOENT")
|
|
24
|
+
return false;
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function accountSlug(email) {
|
|
29
|
+
const normalizedEmail = email.toLowerCase();
|
|
30
|
+
const readableSlug = normalizedEmail
|
|
31
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
32
|
+
.replace(/^-+|-+$/g, "");
|
|
33
|
+
if (readableSlug.length === 0) {
|
|
34
|
+
throw new CliError(EXIT.usage, `could not derive an account slug from: ${email}`);
|
|
35
|
+
}
|
|
36
|
+
const fingerprint = createHash("sha256")
|
|
37
|
+
.update(normalizedEmail)
|
|
38
|
+
.digest("base64url")
|
|
39
|
+
.slice(0, 16);
|
|
40
|
+
return `${readableSlug}-${fingerprint}`;
|
|
41
|
+
}
|
|
42
|
+
export function addAccount({ email, gmail, drive, login, workspaceRoot, }) {
|
|
43
|
+
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
|
|
44
|
+
throw new CliError(EXIT.usage, `invalid email address: ${email}`);
|
|
45
|
+
}
|
|
46
|
+
const scopes = resolveAccountScopes({ gmail, drive });
|
|
47
|
+
const slug = accountSlug(email);
|
|
48
|
+
const root = resolve(workspaceRoot ?? process.cwd());
|
|
49
|
+
const credentialsDir = join(root, "credentials");
|
|
50
|
+
const oauthClient = join(credentialsDir, "google-oauth-client.json");
|
|
51
|
+
const accountDir = join(root, "accounts", slug);
|
|
52
|
+
const configDir = join(accountDir, "gws");
|
|
53
|
+
const accountOauthClient = join(configDir, "client_secret.json");
|
|
54
|
+
const accessProfile = join(configDir, "access.json");
|
|
55
|
+
if (!isFile(oauthClient)) {
|
|
56
|
+
throw new CliError(EXIT.noInput, `OAuth client must be a regular file, not a symlink: ${oauthClient}`);
|
|
57
|
+
}
|
|
58
|
+
const credentialsDirectory = lstatSync(credentialsDir);
|
|
59
|
+
if (!credentialsDirectory.isDirectory() ||
|
|
60
|
+
credentialsDirectory.isSymbolicLink()) {
|
|
61
|
+
throw new CliError(EXIT.noInput, `credentials path must be a regular directory: ${credentialsDir}`);
|
|
62
|
+
}
|
|
63
|
+
chmodSync(credentialsDir, 0o700);
|
|
64
|
+
chmodSync(oauthClient, 0o600);
|
|
65
|
+
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
66
|
+
chmodSync(accountDir, 0o700);
|
|
67
|
+
chmodSync(configDir, 0o700);
|
|
68
|
+
if (pathExists(accountOauthClient)) {
|
|
69
|
+
const accountOauthClientFile = lstatSync(accountOauthClient);
|
|
70
|
+
if (!accountOauthClientFile.isFile() ||
|
|
71
|
+
accountOauthClientFile.isSymbolicLink()) {
|
|
72
|
+
throw new CliError(EXIT.noInput, `account OAuth client must be a regular file: ${accountOauthClient}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
copyFileSync(oauthClient, accountOauthClient);
|
|
76
|
+
chmodSync(accountOauthClient, 0o600);
|
|
77
|
+
const saveAccessProfile = () => {
|
|
78
|
+
writeFileSync(accessProfile, `${JSON.stringify({ email, gmail, drive }, null, 2)}\n`, {
|
|
79
|
+
mode: 0o600,
|
|
80
|
+
});
|
|
81
|
+
chmodSync(accessProfile, 0o600);
|
|
82
|
+
};
|
|
83
|
+
console.log(`Account slug: ${slug}`);
|
|
84
|
+
console.log(`Gmail access: ${gmail}`);
|
|
85
|
+
console.log(`Drive access: ${drive}`);
|
|
86
|
+
if (!login) {
|
|
87
|
+
saveAccessProfile();
|
|
88
|
+
console.log("Skipped OAuth login (--no-login).");
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
const result = spawnSync(process.execPath, [
|
|
92
|
+
process.argv[1] ?? "mgws",
|
|
93
|
+
"run",
|
|
94
|
+
slug,
|
|
95
|
+
"auth",
|
|
96
|
+
"login",
|
|
97
|
+
"--scopes",
|
|
98
|
+
scopes.join(","),
|
|
99
|
+
], { cwd: root, stdio: "inherit" });
|
|
100
|
+
if (result.error) {
|
|
101
|
+
throw new CliError(EXIT.unavailable, `could not start OAuth login: ${result.error.message}`);
|
|
102
|
+
}
|
|
103
|
+
if (result.status !== null) {
|
|
104
|
+
if (result.status === 0)
|
|
105
|
+
saveAccessProfile();
|
|
106
|
+
return result.status;
|
|
107
|
+
}
|
|
108
|
+
throw new CliError(1, `OAuth login terminated by signal ${result.signal ?? "unknown"}`);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=account-add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-add.js","sourceRoot":"","sources":["../src/account-add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const ACCESS_LEVELS: readonly ["none", "read", "manage"];
|
|
2
|
+
export type AccessLevel = (typeof ACCESS_LEVELS)[number];
|
|
3
|
+
export interface AccountAccess {
|
|
4
|
+
gmail: AccessLevel;
|
|
5
|
+
drive: AccessLevel;
|
|
6
|
+
}
|
|
7
|
+
export declare function isAccessLevel(value: string): value is AccessLevel;
|
|
8
|
+
export declare function resolveAccountScopes({ gmail, drive, }: AccountAccess): string[];
|
|
9
|
+
//# sourceMappingURL=account-permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-permissions.d.ts","sourceRoot":"","sources":["../src/account-permissions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,YAAI,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;CACpB;AAkBD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE;AAED,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,KAAK,GACN,EAAE,aAAa,GAAG,MAAM,EAAE,CAM1B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const ACCESS_LEVELS = ["none", "read", "manage"];
|
|
2
|
+
const GMAIL_SCOPES = {
|
|
3
|
+
none: [],
|
|
4
|
+
read: ["https://www.googleapis.com/auth/gmail.readonly"],
|
|
5
|
+
manage: [
|
|
6
|
+
"https://www.googleapis.com/auth/gmail.modify",
|
|
7
|
+
"https://www.googleapis.com/auth/gmail.labels",
|
|
8
|
+
"https://www.googleapis.com/auth/gmail.settings.basic",
|
|
9
|
+
],
|
|
10
|
+
};
|
|
11
|
+
const DRIVE_SCOPES = {
|
|
12
|
+
none: [],
|
|
13
|
+
read: ["https://www.googleapis.com/auth/drive.readonly"],
|
|
14
|
+
manage: ["https://www.googleapis.com/auth/drive"],
|
|
15
|
+
};
|
|
16
|
+
export function isAccessLevel(value) {
|
|
17
|
+
return ACCESS_LEVELS.includes(value);
|
|
18
|
+
}
|
|
19
|
+
export function resolveAccountScopes({ gmail, drive, }) {
|
|
20
|
+
if (gmail === "none" && drive === "none") {
|
|
21
|
+
throw new RangeError("at least one of Gmail or Drive must be enabled");
|
|
22
|
+
}
|
|
23
|
+
return [...GMAIL_SCOPES[gmail], ...DRIVE_SCOPES[drive]];
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=account-permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-permissions.js","sourceRoot":"","sources":["../src/account-permissions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAC;AASjE,MAAM,YAAY,GAA2C;IAC3D,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,CAAC,gDAAgD,CAAC;IACxD,MAAM,EAAE;QACN,8CAA8C;QAC9C,8CAA8C;QAC9C,sDAAsD;KACvD;CACF,CAAC;AAEF,MAAM,YAAY,GAA2C;IAC3D,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,CAAC,gDAAgD,CAAC;IACxD,MAAM,EAAE,CAAC,uCAAuC,CAAC;CAClD,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAoB,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EACnC,KAAK,EACL,KAAK,GACS;IACd,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;QACzC,MAAM,IAAI,UAAU,CAAC,gDAAgD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { Command, CommanderError, Option } from "commander";
|
|
4
|
+
import { addAccount } from "./account-add.js";
|
|
5
|
+
import { ACCESS_LEVELS, isAccessLevel } from "./account-permissions.js";
|
|
6
|
+
import { CliError, EXIT } from "./errors.js";
|
|
7
|
+
import { runGws } from "./run.js";
|
|
8
|
+
const packageMetadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
9
|
+
function accessLevel(value) {
|
|
10
|
+
if (!isAccessLevel(value)) {
|
|
11
|
+
throw new CommanderError(EXIT.usage, "mgws.invalidAccess", `expected one of: ${ACCESS_LEVELS.join(", ")}`);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
|
+
const program = new Command()
|
|
16
|
+
.name("mgws")
|
|
17
|
+
.description(packageMetadata.description)
|
|
18
|
+
.version(packageMetadata.version)
|
|
19
|
+
.showHelpAfterError()
|
|
20
|
+
.exitOverride();
|
|
21
|
+
program
|
|
22
|
+
.command("run")
|
|
23
|
+
.description("Run gws with an isolated account and safety policy")
|
|
24
|
+
.argument("<account>", "account slug")
|
|
25
|
+
.argument("<gws-arguments...>", "arguments forwarded to gws")
|
|
26
|
+
.option("--confirm", "confirm an action that changes external state")
|
|
27
|
+
.allowUnknownOption()
|
|
28
|
+
.action((account, gwsArguments, options) => {
|
|
29
|
+
process.exitCode = runGws({
|
|
30
|
+
account,
|
|
31
|
+
confirmed: options.confirm === true,
|
|
32
|
+
gwsArguments,
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
const account = program
|
|
36
|
+
.command("account")
|
|
37
|
+
.description("Manage isolated Google accounts");
|
|
38
|
+
account
|
|
39
|
+
.command("add")
|
|
40
|
+
.description("Connect a Google account")
|
|
41
|
+
.argument("<email>", "Google account email address")
|
|
42
|
+
.addOption(new Option("--gmail <level>", "Gmail permission level")
|
|
43
|
+
.argParser(accessLevel)
|
|
44
|
+
.makeOptionMandatory())
|
|
45
|
+
.addOption(new Option("--drive <level>", "Drive permission level")
|
|
46
|
+
.argParser(accessLevel)
|
|
47
|
+
.makeOptionMandatory())
|
|
48
|
+
.option("--no-login", "create account state without starting OAuth")
|
|
49
|
+
.action((email, options) => {
|
|
50
|
+
if (!isAccessLevel(options.gmail) || !isAccessLevel(options.drive)) {
|
|
51
|
+
throw new CliError(EXIT.usage, "invalid permission level");
|
|
52
|
+
}
|
|
53
|
+
process.exitCode = addAccount({
|
|
54
|
+
email,
|
|
55
|
+
gmail: options.gmail,
|
|
56
|
+
drive: options.drive,
|
|
57
|
+
login: options.login,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
const rawArguments = process.argv.slice(2);
|
|
62
|
+
const accountSlug = rawArguments[1];
|
|
63
|
+
if (rawArguments[0] === "run" &&
|
|
64
|
+
accountSlug !== undefined &&
|
|
65
|
+
accountSlug !== "--help" &&
|
|
66
|
+
accountSlug !== "-h") {
|
|
67
|
+
const gwsArguments = rawArguments.slice(2);
|
|
68
|
+
const confirmed = gwsArguments[0] === "--confirm";
|
|
69
|
+
if (confirmed)
|
|
70
|
+
gwsArguments.shift();
|
|
71
|
+
process.exitCode = runGws({
|
|
72
|
+
account: accountSlug,
|
|
73
|
+
confirmed,
|
|
74
|
+
gwsArguments,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
program.parse();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof CliError) {
|
|
83
|
+
console.error(`mgws: ${error.message}`);
|
|
84
|
+
process.exitCode = error.status;
|
|
85
|
+
}
|
|
86
|
+
else if (error instanceof CommanderError) {
|
|
87
|
+
process.exitCode = error.exitCode;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const EXIT: {
|
|
2
|
+
readonly usage: 64;
|
|
3
|
+
readonly noInput: 66;
|
|
4
|
+
readonly unavailable: 69;
|
|
5
|
+
readonly noPermission: 77;
|
|
6
|
+
};
|
|
7
|
+
export declare class CliError extends Error {
|
|
8
|
+
readonly status: number;
|
|
9
|
+
constructor(status: number, message: string);
|
|
10
|
+
}
|
|
11
|
+
export declare function errorCode(error: unknown): string | undefined;
|
|
12
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI;aACf,KAAK,EAAE,EAAE;aACT,OAAO,EAAE,EAAE;aACX,WAAW,EAAE,EAAE;aACf,YAAY,EAAE,EAAE;CACR,CAAC;AAEX,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IADzB,YACW,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EAIhB;CACF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAM5D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const EXIT = {
|
|
2
|
+
usage: 64,
|
|
3
|
+
noInput: 66,
|
|
4
|
+
unavailable: 69,
|
|
5
|
+
noPermission: 77,
|
|
6
|
+
};
|
|
7
|
+
export class CliError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(status, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.name = "CliError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function errorCode(error) {
|
|
16
|
+
return error instanceof Error &&
|
|
17
|
+
"code" in error &&
|
|
18
|
+
typeof error.code === "string"
|
|
19
|
+
? error.code
|
|
20
|
+
: undefined;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,EAAE;IACX,WAAW,EAAE,EAAE;IACf,YAAY,EAAE,EAAE;CACR,CAAC;AAEX,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB,MAAM;IADjB,YACW,MAAc,EACvB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;sBAHN,MAAM;QAIf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,KAAK;QAC3B,MAAM,IAAI,KAAK;QACf,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,CAAC,CAAC,KAAK,CAAC,IAAI;QACZ,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type CommandPolicy = {
|
|
2
|
+
action: "allow";
|
|
3
|
+
} | {
|
|
4
|
+
action: "confirm";
|
|
5
|
+
reason: string;
|
|
6
|
+
} | {
|
|
7
|
+
action: "prohibit";
|
|
8
|
+
reason: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function classifyGwsCommand(args: readonly string[]): CommandPolicy;
|
|
11
|
+
//# sourceMappingURL=gws-command-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gws-command-policy.d.ts","sourceRoot":"","sources":["../src/gws-command-policy.ts"],"names":[],"mappings":"AAmCA,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA0B3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CA+CzE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const GMAIL_CONFIRM_ALIASES = new Set([
|
|
2
|
+
"+send",
|
|
3
|
+
"+reply",
|
|
4
|
+
"+reply-all",
|
|
5
|
+
"+forward",
|
|
6
|
+
]);
|
|
7
|
+
const GMAIL_PROHIBITED_METHODS = new Set([
|
|
8
|
+
"messages:delete",
|
|
9
|
+
"messages:batchDelete",
|
|
10
|
+
"threads:delete",
|
|
11
|
+
"drafts:delete",
|
|
12
|
+
]);
|
|
13
|
+
const GMAIL_CONFIRM_METHODS = new Set(["drafts:send", "messages:send"]);
|
|
14
|
+
const DRIVE_PROHIBITED_METHODS = new Set([
|
|
15
|
+
"files:delete",
|
|
16
|
+
"files:emptyTrash",
|
|
17
|
+
"revisions:delete",
|
|
18
|
+
]);
|
|
19
|
+
const DRIVE_CONFIRM_METHODS = new Set([
|
|
20
|
+
"permissions:create",
|
|
21
|
+
"permissions:update",
|
|
22
|
+
"permissions:delete",
|
|
23
|
+
]);
|
|
24
|
+
const GWS_VALUE_FLAGS = new Set([
|
|
25
|
+
"--api-version",
|
|
26
|
+
"--format",
|
|
27
|
+
"--json",
|
|
28
|
+
"--output",
|
|
29
|
+
"--page-delay",
|
|
30
|
+
"--page-limit",
|
|
31
|
+
"--params",
|
|
32
|
+
"--upload",
|
|
33
|
+
"--upload-content-type",
|
|
34
|
+
]);
|
|
35
|
+
function positionalArguments(args) {
|
|
36
|
+
const positional = [];
|
|
37
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
38
|
+
const argument = args[index];
|
|
39
|
+
if (argument === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
if (!argument.startsWith("--")) {
|
|
42
|
+
positional.push(argument);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const flag = argument.split("=", 1)[0];
|
|
46
|
+
if (flag !== undefined &&
|
|
47
|
+
GWS_VALUE_FLAGS.has(flag) &&
|
|
48
|
+
!argument.includes("=")) {
|
|
49
|
+
index += 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return positional;
|
|
53
|
+
}
|
|
54
|
+
export function classifyGwsCommand(args) {
|
|
55
|
+
const [serviceWithVersion, resource, collection, method] = positionalArguments(args);
|
|
56
|
+
const service = serviceWithVersion?.split(":", 1)[0];
|
|
57
|
+
if (service === "gmail") {
|
|
58
|
+
if (resource !== undefined && GMAIL_CONFIRM_ALIASES.has(resource)) {
|
|
59
|
+
return {
|
|
60
|
+
action: "confirm",
|
|
61
|
+
reason: "Sending email requires explicit confirmation",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (resource === "users") {
|
|
65
|
+
const operation = `${collection ?? ""}:${method ?? ""}`;
|
|
66
|
+
if (GMAIL_PROHIBITED_METHODS.has(operation)) {
|
|
67
|
+
return {
|
|
68
|
+
action: "prohibit",
|
|
69
|
+
reason: "Permanent Gmail deletion is prohibited",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (GMAIL_CONFIRM_METHODS.has(operation)) {
|
|
73
|
+
return {
|
|
74
|
+
action: "confirm",
|
|
75
|
+
reason: "Sending email requires explicit confirmation",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (service === "drive") {
|
|
81
|
+
const operation = `${resource ?? ""}:${collection ?? ""}`;
|
|
82
|
+
if (DRIVE_PROHIBITED_METHODS.has(operation)) {
|
|
83
|
+
return {
|
|
84
|
+
action: "prohibit",
|
|
85
|
+
reason: "Permanent Drive deletion is prohibited",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (DRIVE_CONFIRM_METHODS.has(operation)) {
|
|
89
|
+
return {
|
|
90
|
+
action: "confirm",
|
|
91
|
+
reason: "Drive permission changes require explicit confirmation",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return { action: "allow" };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=gws-command-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gws-command-policy.js","sourceRoot":"","sources":["../src/gws-command-policy.ts"],"names":[],"mappings":"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"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface RunOptions {
|
|
2
|
+
account: string;
|
|
3
|
+
confirmed: boolean;
|
|
4
|
+
gwsArguments: string[];
|
|
5
|
+
workspaceRoot?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function resolveFileArguments(args: readonly string[], root: string): string[];
|
|
8
|
+
export declare function runGws({ account, confirmed, gwsArguments, workspaceRoot, }: RunOptions): number;
|
|
9
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AA0DD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAiCV;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,SAAS,EACT,YAAY,EACZ,aAAa,GACd,EAAE,UAAU,GAAG,MAAM,CAgFrB"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { accessSync, chmodSync, constants, lstatSync, mkdirSync, statSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { CliError, EXIT, errorCode } from "./errors.js";
|
|
6
|
+
import { classifyGwsCommand } from "./gws-command-policy.js";
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const FILE_PATH_FLAGS = new Set(["--output", "--upload"]);
|
|
9
|
+
function isDirectory(path) {
|
|
10
|
+
try {
|
|
11
|
+
return statSync(path).isDirectory();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (errorCode(error) === "ENOENT")
|
|
15
|
+
return false;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function isExecutable(path) {
|
|
20
|
+
try {
|
|
21
|
+
accessSync(path, constants.X_OK);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isFile(path) {
|
|
29
|
+
try {
|
|
30
|
+
return statSync(path).isFile();
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (errorCode(error) === "ENOENT")
|
|
34
|
+
return false;
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function ensureRuntimeDirectory(path) {
|
|
39
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
40
|
+
const directory = lstatSync(path);
|
|
41
|
+
if (!directory.isDirectory() || directory.isSymbolicLink()) {
|
|
42
|
+
throw new CliError(EXIT.noPermission, `unsafe runtime directory: ${path}`);
|
|
43
|
+
}
|
|
44
|
+
chmodSync(path, 0o700);
|
|
45
|
+
const dotenv = join(path, ".env");
|
|
46
|
+
try {
|
|
47
|
+
writeFileSync(dotenv, "", { flag: "wx", mode: 0o600 });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (errorCode(error) !== "EEXIST")
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
const dotenvFile = lstatSync(dotenv);
|
|
54
|
+
if (!dotenvFile.isFile() ||
|
|
55
|
+
dotenvFile.isSymbolicLink() ||
|
|
56
|
+
dotenvFile.size !== 0) {
|
|
57
|
+
throw new CliError(EXIT.noPermission, `unsafe runtime environment file: ${dotenv}`);
|
|
58
|
+
}
|
|
59
|
+
chmodSync(dotenv, 0o600);
|
|
60
|
+
}
|
|
61
|
+
export function resolveFileArguments(args, root) {
|
|
62
|
+
const resolvedArgs = [];
|
|
63
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
64
|
+
const argument = args[index];
|
|
65
|
+
if (argument === undefined)
|
|
66
|
+
continue;
|
|
67
|
+
if (FILE_PATH_FLAGS.has(argument) && index + 1 < args.length) {
|
|
68
|
+
const value = args[index + 1];
|
|
69
|
+
if (value !== undefined) {
|
|
70
|
+
resolvedArgs.push(argument, value === "-" || isAbsolute(value) ? value : resolve(root, value));
|
|
71
|
+
index += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const inlineFlag = [...FILE_PATH_FLAGS].find((flag) => argument.startsWith(`${flag}=`));
|
|
76
|
+
if (inlineFlag !== undefined) {
|
|
77
|
+
const value = argument.slice(inlineFlag.length + 1);
|
|
78
|
+
resolvedArgs.push(`${inlineFlag}=${value === "-" || isAbsolute(value) ? value : resolve(root, value)}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
resolvedArgs.push(argument);
|
|
82
|
+
}
|
|
83
|
+
return resolvedArgs;
|
|
84
|
+
}
|
|
85
|
+
export function runGws({ account, confirmed, gwsArguments, workspaceRoot, }) {
|
|
86
|
+
if (!/^[A-Za-z0-9._-]+$/.test(account) ||
|
|
87
|
+
account.startsWith(".") ||
|
|
88
|
+
account.includes("..")) {
|
|
89
|
+
throw new CliError(EXIT.usage, `invalid account slug: ${account}`);
|
|
90
|
+
}
|
|
91
|
+
if (gwsArguments.length === 0) {
|
|
92
|
+
throw new CliError(EXIT.usage, "missing gws arguments");
|
|
93
|
+
}
|
|
94
|
+
const root = resolve(workspaceRoot ?? process.cwd());
|
|
95
|
+
const configDir = join(root, "accounts", account, "gws");
|
|
96
|
+
const runtimeDir = join(configDir, ".runtime");
|
|
97
|
+
const gwsOverride = process.env.GWS_EXECUTABLE;
|
|
98
|
+
const gwsEntrypoint = require.resolve("@googleworkspace/cli/run.js");
|
|
99
|
+
const gwsExecutable = gwsOverride ?? process.execPath;
|
|
100
|
+
const gwsPrefixArgs = gwsOverride === undefined ? [gwsEntrypoint] : [];
|
|
101
|
+
if (!isDirectory(configDir)) {
|
|
102
|
+
throw new CliError(EXIT.noInput, `unknown account: ${account}\nask your agent to use $add-account to connect it`);
|
|
103
|
+
}
|
|
104
|
+
if (gwsOverride !== undefined
|
|
105
|
+
? !isExecutable(gwsExecutable)
|
|
106
|
+
: !isFile(gwsEntrypoint)) {
|
|
107
|
+
throw new CliError(EXIT.unavailable, "gws is not installed; run: npm install");
|
|
108
|
+
}
|
|
109
|
+
const policy = classifyGwsCommand(gwsArguments);
|
|
110
|
+
if (policy.action === "prohibit")
|
|
111
|
+
throw new CliError(EXIT.noPermission, policy.reason);
|
|
112
|
+
if (policy.action === "confirm" && !confirmed) {
|
|
113
|
+
throw new CliError(EXIT.noPermission, `${policy.reason}\nafter confirmation, rerun with --confirm after the account slug`);
|
|
114
|
+
}
|
|
115
|
+
ensureRuntimeDirectory(runtimeDir);
|
|
116
|
+
const gwsEnv = { ...process.env };
|
|
117
|
+
delete gwsEnv.GOOGLE_WORKSPACE_CLI_CLIENT_ID;
|
|
118
|
+
delete gwsEnv.GOOGLE_WORKSPACE_CLI_CLIENT_SECRET;
|
|
119
|
+
delete gwsEnv.GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE;
|
|
120
|
+
const result = spawnSync(gwsExecutable, [...gwsPrefixArgs, ...resolveFileArguments(gwsArguments, root)], {
|
|
121
|
+
cwd: runtimeDir,
|
|
122
|
+
env: {
|
|
123
|
+
...gwsEnv,
|
|
124
|
+
GOOGLE_APPLICATION_CREDENTIALS: join(runtimeDir, ".env", "no-adc"),
|
|
125
|
+
GOOGLE_WORKSPACE_CLI_CONFIG_DIR: configDir,
|
|
126
|
+
GOOGLE_WORKSPACE_CLI_KEYRING_BACKEND: "keyring",
|
|
127
|
+
GOOGLE_WORKSPACE_CLI_TOKEN: "",
|
|
128
|
+
},
|
|
129
|
+
stdio: "inherit",
|
|
130
|
+
});
|
|
131
|
+
if (result.error) {
|
|
132
|
+
throw new CliError(EXIT.unavailable, `could not run gws: ${result.error.message}`);
|
|
133
|
+
}
|
|
134
|
+
if (result.status !== null)
|
|
135
|
+
return result.status;
|
|
136
|
+
throw new CliError(1, `gws terminated by signal ${result.signal ?? "unknown"}`);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "multi-gws",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Multi-account safety wrapper for the Google Workspace CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mgws": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.json",
|
|
14
|
+
"check": "npm run lint && npm run test && npm run build",
|
|
15
|
+
"format": "biome format --write .",
|
|
16
|
+
"lint": "biome check .",
|
|
17
|
+
"prepack": "npm run build",
|
|
18
|
+
"release": "node scripts/release.mjs",
|
|
19
|
+
"test": "vitest run"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=22.9.0"
|
|
23
|
+
},
|
|
24
|
+
"packageManager": "npm@11.18.0",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@googleworkspace/cli": "0.22.5",
|
|
27
|
+
"commander": "14.0.3"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@biomejs/biome": "2.5.5",
|
|
31
|
+
"@types/node": "26.1.1",
|
|
32
|
+
"typescript": "7.0.2",
|
|
33
|
+
"vitest": "4.1.10"
|
|
34
|
+
},
|
|
35
|
+
"allowScripts": {
|
|
36
|
+
"@googleworkspace/cli@0.22.5": true
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/rarexlabs/mgws.git"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/rarexlabs/mgws/issues"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/rarexlabs/mgws#readme",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"keywords": [
|
|
51
|
+
"google-workspace",
|
|
52
|
+
"gws",
|
|
53
|
+
"multi-account",
|
|
54
|
+
"cli"
|
|
55
|
+
]
|
|
56
|
+
}
|