pentect 0.0.33 → 0.0.34

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <a href="https://pentect.dev/">
3
- <img src="website/public/pentect-logo-transparent.png" width="96" alt="Pentect">
3
+ <img src="https://pentect.dev/pentect-logo-transparent.png" width="96" alt="Pentect">
4
4
  </a>
5
5
  </p>
6
6
 
@@ -31,6 +31,11 @@ providers. Start with the [documentation](https://pentect.dev/).
31
31
  - [Contributing](CONTRIBUTING.md)
32
32
  - [Third-party notices](THIRD_PARTY_LICENSES.txt)
33
33
 
34
+ > **Security scope:** Pentect does not protect a compromised operating system
35
+ > from malware with administrator privileges or an attacker that can read local
36
+ > process memory. It reduces unintended disclosure of sensitive data to AI
37
+ > providers.
38
+
34
39
  ## License
35
40
 
36
41
  [MIT](LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentect",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "type": "module",
5
5
  "description": "Local secret masking boundary for AI agents",
6
6
  "license": "MIT",
@@ -20,7 +20,6 @@
20
20
  "README.md"
21
21
  ],
22
22
  "scripts": {
23
- "postinstall": "node packaging/npm/install.js",
24
23
  "test": "node --test packaging/npm/*.test.js"
25
24
  },
26
25
  "engines": {
@@ -1,8 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from 'node:child_process';
3
- import { fileURLToPath } from 'node:url';
3
+ import { ensureInstalled } from '../install.js';
4
+
5
+ let executable;
6
+ try {
7
+ executable = await ensureInstalled();
8
+ } catch (error) {
9
+ console.error(`pentect: ${error.message}`);
10
+ process.exit(1);
11
+ }
4
12
 
5
- const executable = fileURLToPath(new URL(`../vendor/${process.platform === 'win32' ? 'pentect.exe' : 'pentect'}`, import.meta.url));
6
13
  const result = spawnSync(executable, process.argv.slice(2), { stdio: 'inherit' });
7
14
  if (result.error) {
8
15
  console.error(`pentect: ${result.error.message}`);
@@ -1,12 +1,30 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
2
+ import { access, chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
3
4
  import { dirname, join, resolve } from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { gunzipSync } from 'node:zlib';
6
7
 
7
8
  const repository = 'EdamAme-x/pentect';
8
9
  const packageRoot = fileURLToPath(new URL('../..', import.meta.url));
9
- const destination = join(packageRoot, 'packaging', 'npm', 'vendor', process.platform === 'win32' ? 'pentect.exe' : 'pentect');
10
+
11
+ function cacheBase(environment = process.env, platform = process.platform, home = homedir()) {
12
+ if (environment.PENTECT_NPM_CACHE) return resolve(environment.PENTECT_NPM_CACHE);
13
+ if (platform === 'win32') {
14
+ return resolve(environment.LOCALAPPDATA || join(home, 'AppData', 'Local'), 'Pentect', 'npm');
15
+ }
16
+ if (platform === 'darwin') return resolve(home, 'Library', 'Caches', 'Pentect', 'npm');
17
+ return resolve(environment.XDG_CACHE_HOME || join(home, '.cache'), 'pentect', 'npm');
18
+ }
19
+
20
+ export function installationPath(version, options = {}) {
21
+ if (!/^[0-9A-Za-z][0-9A-Za-z._+-]{0,63}$/.test(version) || version === '..') {
22
+ throw new Error('The Pentect package version is invalid');
23
+ }
24
+ const platform = options.platform || process.platform;
25
+ const base = cacheBase(options.environment, platform, options.home);
26
+ return join(base, version, platform === 'win32' ? 'pentect.exe' : 'pentect');
27
+ }
10
28
 
11
29
  export function releaseAsset(platform = process.platform, architecture = process.arch) {
12
30
  const assets = {
@@ -27,6 +45,11 @@ export function expectedChecksum(text) {
27
45
  return match[1].toLowerCase();
28
46
  }
29
47
 
48
+ async function packageVersion() {
49
+ const metadata = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'));
50
+ return metadata.version?.replace(/^v/, '');
51
+ }
52
+
30
53
  async function download(url, signal) {
31
54
  const response = await fetch(url, {
32
55
  redirect: 'follow',
@@ -50,10 +73,10 @@ async function downloadBinary(base, asset, signal) {
50
73
  return download(`${base}/${asset}`, signal);
51
74
  }
52
75
 
53
- export async function install() {
76
+ export async function install(version) {
77
+ version ||= await packageVersion();
54
78
  const asset = releaseAsset();
55
- const metadata = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'));
56
- const version = (process.env.PENTECT_VERSION || metadata.version)?.replace(/^v/, '');
79
+ const destination = installationPath(version);
57
80
  const tag = version ? `v${version}` : 'latest';
58
81
  const base = tag === 'latest'
59
82
  ? `https://github.com/${repository}/releases/latest/download`
@@ -74,9 +97,28 @@ export async function install() {
74
97
  await rm(destination, { force: true });
75
98
  await rename(temporary, destination);
76
99
  if (process.platform !== 'win32') await chmod(destination, 0o755);
100
+ await writeFile(join(dirname(destination), '.pentect-managed-install.json'), JSON.stringify({
101
+ version: 1,
102
+ manager: 'npm',
103
+ update: 'npm update -g pentect',
104
+ uninstall: 'npm uninstall -g pentect',
105
+ }), { mode: 0o600 });
77
106
  } finally {
78
107
  await rm(temporary, { force: true });
79
108
  }
109
+ return destination;
110
+ }
111
+
112
+ export async function ensureInstalled() {
113
+ const version = await packageVersion();
114
+ const destination = installationPath(version);
115
+ try {
116
+ await access(destination);
117
+ return destination;
118
+ } catch (error) {
119
+ if (error?.code !== 'ENOENT') throw error;
120
+ }
121
+ return install(version);
80
122
  }
81
123
 
82
124
  const invokedDirectly = process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);