dsh-git-branch-manage 1.1.0 → 1.2.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.
- package/CHANGELOG.md +17 -0
- package/lib/client.js +82 -16
- package/lib/credential-service.d.ts +32 -38
- package/lib/credential-service.js +56 -27
- package/lib/credentials.d.ts +145 -40
- package/lib/credentials.js +398 -70
- package/lib/index.js +24 -18
- package/lib/local-import.d.ts +68 -0
- package/lib/local-import.js +151 -0
- package/lib/network-tool.d.ts +5 -8
- package/lib/network-tool.js +14 -18
- package/lib/routes.d.ts +19 -2
- package/lib/routes.js +62 -19
- package/lib/shell-bridge.d.ts +57 -115
- package/lib/shell-bridge.js +96 -170
- package/lib/tool.js +2 -2
- package/lib/wire.d.ts +29 -0
- package/lib/wire.js +3 -0
- package/package.json +1 -1
- package/lib/helpers/git-credential-bridge.d.ts +0 -37
- package/lib/helpers/git-credential-bridge.js +0 -119
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standalone git credential helper shipped with the dsh-git-branch plugin.
|
|
3
|
-
*
|
|
4
|
-
* The panel's credential file (`~/.dsh/git-credentials.json`) normally rides
|
|
5
|
-
* `-c http.<url>.extraHeader` config on the routes and the `git_network` tool.
|
|
6
|
-
* This helper extends that coverage to a plain shell `git push`: the plugin's
|
|
7
|
-
* host process writes a session gitconfig (see `src/shell-bridge.ts`) that
|
|
8
|
-
* installs this script as a URL-scoped credential helper for every stored
|
|
9
|
-
* host, so commands the model runs in the shell authenticate as the
|
|
10
|
-
* configured account too.
|
|
11
|
-
*
|
|
12
|
-
* Design constraints (see docs/decisions/0029, 0032 and 0034):
|
|
13
|
-
* - The user's global git config and credential helpers are never written;
|
|
14
|
-
* the injection lives in one generated session config plus the process
|
|
15
|
-
* environment only.
|
|
16
|
-
* - The token never enters the conversation: this script reads the
|
|
17
|
-
* credential file directly on the host and answers git on stdout.
|
|
18
|
-
* - URL scope (`credential.https://<host>/`) confines the helper to hosts
|
|
19
|
-
* with a stored credential. The host half also clears the machine helper
|
|
20
|
-
* list, so a host this script cannot answer fails fast instead of opening
|
|
21
|
-
* an interactive credential dialog.
|
|
22
|
-
* - `get` is silent on a miss (git falls through to the next helper);
|
|
23
|
-
* `store`/`erase` are pass-through by decision — writing back would race
|
|
24
|
-
* the panel's atomic save and leak the file shape.
|
|
25
|
-
*
|
|
26
|
-
* Environment contract (set by src/shell-bridge.ts). The names carry no
|
|
27
|
-
* KEY/PASSWORD/SECRET/TOKEN substring and no `DSH_` prefix, because the DSH
|
|
28
|
-
* subprocess scrubber strips exactly those from inherited environments
|
|
29
|
-
* (decision 0034; a stripped path made this helper read the wrong file):
|
|
30
|
-
* - `DGB_BRIDGE_HELPER` — credential file path (required).
|
|
31
|
-
* - `DGB_BRIDGE_HOME` — user home directory (fallback resolution).
|
|
32
|
-
* - `DGB_BRIDGE_DSH_HOME` — `$DSH_HOME` override (optional).
|
|
33
|
-
* - `DGB_BRIDGE_DEBUG` — when non-blank, a debug log path (optional).
|
|
34
|
-
*
|
|
35
|
-
* @module dsh-git-branch/git-credential-bridge
|
|
36
|
-
*/
|
|
37
|
-
export {};
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standalone git credential helper shipped with the dsh-git-branch plugin.
|
|
3
|
-
*
|
|
4
|
-
* The panel's credential file (`~/.dsh/git-credentials.json`) normally rides
|
|
5
|
-
* `-c http.<url>.extraHeader` config on the routes and the `git_network` tool.
|
|
6
|
-
* This helper extends that coverage to a plain shell `git push`: the plugin's
|
|
7
|
-
* host process writes a session gitconfig (see `src/shell-bridge.ts`) that
|
|
8
|
-
* installs this script as a URL-scoped credential helper for every stored
|
|
9
|
-
* host, so commands the model runs in the shell authenticate as the
|
|
10
|
-
* configured account too.
|
|
11
|
-
*
|
|
12
|
-
* Design constraints (see docs/decisions/0029, 0032 and 0034):
|
|
13
|
-
* - The user's global git config and credential helpers are never written;
|
|
14
|
-
* the injection lives in one generated session config plus the process
|
|
15
|
-
* environment only.
|
|
16
|
-
* - The token never enters the conversation: this script reads the
|
|
17
|
-
* credential file directly on the host and answers git on stdout.
|
|
18
|
-
* - URL scope (`credential.https://<host>/`) confines the helper to hosts
|
|
19
|
-
* with a stored credential. The host half also clears the machine helper
|
|
20
|
-
* list, so a host this script cannot answer fails fast instead of opening
|
|
21
|
-
* an interactive credential dialog.
|
|
22
|
-
* - `get` is silent on a miss (git falls through to the next helper);
|
|
23
|
-
* `store`/`erase` are pass-through by decision — writing back would race
|
|
24
|
-
* the panel's atomic save and leak the file shape.
|
|
25
|
-
*
|
|
26
|
-
* Environment contract (set by src/shell-bridge.ts). The names carry no
|
|
27
|
-
* KEY/PASSWORD/SECRET/TOKEN substring and no `DSH_` prefix, because the DSH
|
|
28
|
-
* subprocess scrubber strips exactly those from inherited environments
|
|
29
|
-
* (decision 0034; a stripped path made this helper read the wrong file):
|
|
30
|
-
* - `DGB_BRIDGE_HELPER` — credential file path (required).
|
|
31
|
-
* - `DGB_BRIDGE_HOME` — user home directory (fallback resolution).
|
|
32
|
-
* - `DGB_BRIDGE_DSH_HOME` — `$DSH_HOME` override (optional).
|
|
33
|
-
* - `DGB_BRIDGE_DEBUG` — when non-blank, a debug log path (optional).
|
|
34
|
-
*
|
|
35
|
-
* @module dsh-git-branch/git-credential-bridge
|
|
36
|
-
*/
|
|
37
|
-
import { appendFileSync, readFileSync } from 'node:fs';
|
|
38
|
-
import { homedir } from 'node:os';
|
|
39
|
-
import { join } from 'node:path';
|
|
40
|
-
/** git helpers receive exactly one argument: the operation. */
|
|
41
|
-
const OPERATION = process.argv[2] ?? 'get';
|
|
42
|
-
/** The credential file this helper reads (`DGB_BRIDGE_HELPER` wins). */
|
|
43
|
-
const DEFAULT_CREDENTIAL_FILE = 'git-credentials.json';
|
|
44
|
-
/** The dsh home directory below the user profile when `$DSH_HOME` is unset. */
|
|
45
|
-
const PACKAGE_HOME = '.dsh';
|
|
46
|
-
/** The Basic-auth name a token without a username is sent under. */
|
|
47
|
-
const TOKEN_USERNAME = 'oauth2';
|
|
48
|
-
/**
|
|
49
|
-
* Append one debug line behind the user's back; a broken log path must never
|
|
50
|
-
* break the credential lookup.
|
|
51
|
-
*/
|
|
52
|
-
function debug(line) {
|
|
53
|
-
const path = process.env.DGB_BRIDGE_DEBUG;
|
|
54
|
-
if (path === undefined || path.trim() === '')
|
|
55
|
-
return;
|
|
56
|
-
try {
|
|
57
|
-
appendFileSync(path, `${line}\n`, 'utf8');
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
// Deliberately swallowed: debugging is best-effort.
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/** The credential file this helper reads (`DGB_BRIDGE_HELPER` wins). */
|
|
64
|
-
function credentialFile() {
|
|
65
|
-
const helper = process.env.DGB_BRIDGE_HELPER;
|
|
66
|
-
if (helper !== undefined && helper.trim() !== '')
|
|
67
|
-
return helper;
|
|
68
|
-
const dshHome = process.env.DGB_BRIDGE_DSH_HOME;
|
|
69
|
-
const home = dshHome !== undefined && dshHome.trim() !== ''
|
|
70
|
-
? dshHome
|
|
71
|
-
: process.env.DGB_BRIDGE_HOME ?? homedir();
|
|
72
|
-
return join(home, PACKAGE_HOME, DEFAULT_CREDENTIAL_FILE);
|
|
73
|
-
}
|
|
74
|
-
/** One `key=value` request from git on stdin. */
|
|
75
|
-
function readRequest() {
|
|
76
|
-
const text = readFileSync(0, 'utf8');
|
|
77
|
-
const request = new Map();
|
|
78
|
-
for (const line of text.split('\n')) {
|
|
79
|
-
const at = line.indexOf('=');
|
|
80
|
-
if (at > 0)
|
|
81
|
-
request.set(line.slice(0, at), line.slice(at + 1));
|
|
82
|
-
}
|
|
83
|
-
return request;
|
|
84
|
-
}
|
|
85
|
-
/** The stored credential for one host, or undefined when there is none. */
|
|
86
|
-
function readCredential(host) {
|
|
87
|
-
let parsed;
|
|
88
|
-
try {
|
|
89
|
-
parsed = JSON.parse(readFileSync(credentialFile(), 'utf8'));
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
debug(`read failed: ${String(error)}`);
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
const credentials = parsed.credentials;
|
|
96
|
-
if (!Array.isArray(credentials))
|
|
97
|
-
return undefined;
|
|
98
|
-
const entry = credentials.find((item) => typeof item === 'object' && item !== null && item.host === host);
|
|
99
|
-
if (entry === undefined)
|
|
100
|
-
return undefined;
|
|
101
|
-
const secret = typeof entry.secret === 'string' ? entry.secret : '';
|
|
102
|
-
if (secret === '')
|
|
103
|
-
return undefined;
|
|
104
|
-
const username = typeof entry.username === 'string' && entry.username.trim() !== ''
|
|
105
|
-
? entry.username
|
|
106
|
-
: TOKEN_USERNAME;
|
|
107
|
-
return { username, secret };
|
|
108
|
-
}
|
|
109
|
-
if (OPERATION === 'get') {
|
|
110
|
-
const request = readRequest();
|
|
111
|
-
const host = request.get('host') ?? '';
|
|
112
|
-
debug(`get host=${host} protocol=${request.get('protocol') ?? ''}`);
|
|
113
|
-
const credential = readCredential(host);
|
|
114
|
-
if (credential !== undefined) {
|
|
115
|
-
process.stdout.write(`username=${credential.username}\npassword=${credential.secret}\n`);
|
|
116
|
-
}
|
|
117
|
-
// A miss stays silent: git tries the next helper in the chain.
|
|
118
|
-
}
|
|
119
|
-
// `store` / `erase` are deliberate no-ops (see the header comment).
|