@procedures/archive 0.4.0 → 0.6.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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # @procedures/archive
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Patch Changes
6
+
7
+ - @procedures/client@0.6.0
8
+
9
+ ## 0.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 1d55b43: A root for the files of the archive procedures (roadmap R33): `createArchiveModule({ root })` confines each path of the inputs to one folder, with the rules of `createFsModule({ root })`.
14
+
15
+ - A relative path starts at the root. Without `cwd`, the files of `archive.create` start at the root.
16
+ - The archive of each procedure must be in the root. So must the `source`, the `cwd`, the folder of each file and the `target`.
17
+ - A path outside the root gives `FORBIDDEN` with the reason `outside-root`. These are `..` out of the root, an absolute path outside it, another drive, and a link or a junction that leads out.
18
+ - The check uses the real path, also for a path that does not exist yet.
19
+ - The extract keeps its checks of the entries in the target folder ("zip slip"), and the target folder must be in the root.
20
+ - Without a root, the procedures work as before.
21
+ - The new exports: `OUTSIDE_ROOT`, `isInside` and `isOutsideRoot`.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [0f75644]
26
+ - Updated dependencies [09e5566]
27
+ - Updated dependencies [ab77f75]
28
+ - Updated dependencies [a47bee6]
29
+ - Updated dependencies [bc74091]
30
+ - @procedures/client@0.5.0
31
+
3
32
  ## 0.4.0
4
33
 
5
34
  ### Patch Changes
package/README.md CHANGED
@@ -44,18 +44,36 @@ The extract reads all the entries first. It refuses the archive, and writes noth
44
44
  - With `overwrite: true`, the extract removes an old file or link before it writes the new file. A write thus does not go through a link or into a hard link.
45
45
  - The tar extract also keeps the protections of node-tar: it does not write through a symbolic link, and each warning is an error.
46
46
 
47
+ ## The root
48
+
49
+ Without a root, the procedures read and write each path that the process can reach. `createArchiveModule({ root })` confines each path of the inputs to one folder (roadmap R33). The rules are the rules of `createFsModule({ root })` of `@procedures/fs`:
50
+
51
+ ```ts
52
+ import { createRegistry } from "@procedures/client";
53
+ import { createArchiveModule } from "@procedures/archive/module";
54
+
55
+ const registry = createRegistry(createArchiveModule({ root: "/srv/files" }));
56
+ ```
57
+
58
+ - A relative path of an input starts at the root, not at the working folder. Without `cwd`, the files of `archive.create` start at the root.
59
+ - The archive of each procedure, the `source`, the `cwd` and the `target` must be in the root. The folder of each file of `files` must be in the root too.
60
+ - A path outside the root gives `FORBIDDEN` with the reason `outside-root`. This includes `..` out of the root, an absolute path outside it, another drive, and a symbolic link or a junction that leads out.
61
+ - The check uses the real path. For a path that does not exist yet, it uses the real path of the nearest existing folder. A link whose target does not exist yet thus cannot lead a write out of the root.
62
+ - A link in the input goes into the archive as a link. The walk does not read its target.
63
+ - The extract keeps its check of the entries in the target folder, and the target folder is in the root. An extract thus stays in the root.
64
+ - A relative root starts at the working folder of the process. The root must exist when a call starts.
65
+ - `isOutsideRoot(error)` tells the refusal of the root. On Windows, the comparison ignores the case of the letters.
66
+
47
67
  ## Limits
48
68
 
49
69
  | Option | Meaning |
50
70
  |---|---|
51
71
  | `maxBytes` | The most bytes of the files of one archive. The default is 1 GiB. |
52
72
  | `maxEntries` | The most entries of one archive. The default is 100000. |
73
+ | `root` | The folder that confines each path (refer to [The root](#the-root)). The default is no root. |
53
74
 
54
75
  ```ts
55
- import { createRegistry } from "@procedures/client";
56
- import { createArchiveModule } from "@procedures/archive/module";
57
-
58
- const registry = createRegistry(createArchiveModule({ maxBytes: 100 * 1024 * 1024 }));
76
+ const registry = createRegistry(createArchiveModule({ maxBytes: 100 * 1024 * 1024, root: "/srv/files" }));
59
77
  ```
60
78
 
61
79
  - The extract adds the declared sizes before it writes a file. An archive over a limit gives `TOO_LARGE` and changes nothing.
@@ -84,13 +102,18 @@ const registry = createRegistry(createArchiveModule({ maxBytes: 100 * 1024 * 102
84
102
  | `UNSAFE_LINK` | A link goes out of the target, or a hard link names no earlier file. |
85
103
  | `UNSUPPORTED_ENTRY` | The archive or the source has a special file. |
86
104
  | `TOO_LARGE` | The archive has more entries or more bytes than the limits. |
105
+ | `FORBIDDEN` | A path is outside the root of the module (the reason `outside-root`). |
87
106
 
88
- Each error is an `ArchiveError`. Its `entry` names the entry of the archive, when an entry is the cause.
107
+ The errors of the archives are an `ArchiveError`. Its `entry` names the entry of the archive, when an entry is the cause. The refusal of the root is an `InvocationError`, as in `@procedures/fs`.
89
108
 
90
109
  ## MCP
91
110
 
92
- `archive.list` changes nothing, and it is a good tool. `archive.create` and `archive.extract` write files in each folder that the host can reach. A host gives them to Claude only with a root for its files.
111
+ `archive.list` changes nothing, and it is a good tool. Without a root, `archive.create` and `archive.extract` write files in each folder that the host can reach. A host gives them to Claude only with `createArchiveModule({ root })`.
93
112
 
94
113
  ## Tests
95
114
 
96
- `pnpm --filter @procedures/archive test` examines the procedures in temporary folders. The tests make hostile archives: entries with `..` and absolute paths, and links out of the target. Other hostile archives have links that escape together, a zip bomb and a wrong CRC-32. The tests of links in the target folder need the permission to make a symbolic link. Windows without the developer mode thus skips them.
115
+ `pnpm --filter @procedures/archive test` examines the procedures in temporary folders. The tests make hostile archives: entries with `..` and absolute paths, and links out of the target. Other hostile archives have links that escape together, a zip bomb and a wrong CRC-32.
116
+
117
+ - The tests of the root refuse each kind of path for the archive and for the target. These are `..`, an absolute path, another drive, and a link out of the root.
118
+ - The tests of a link to a folder use a junction on Windows, so they need no permission.
119
+ - The tests of a link to a file and of the links in the target folder need the permission to make a symbolic link. Windows without the developer mode thus skips them. The Windows job of the nightly workflow runs them.