@knpkv/herdr-tailscale 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 knpkv
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,13 @@
1
+ # `@knpkv/herdr-tailscale`
2
+
3
+ Read-only Tailscale adapter for Herdr fleet discovery and caller authentication.
4
+
5
+ The Effect service runs only these commands:
6
+
7
+ - `tailscale status --json`
8
+ - `tailscale whois --json <address>`
9
+ - `tailscale ip -4`
10
+
11
+ Each command has a ten-second timeout. JSON is decoded with Schema before it reaches callers. Command, decode, and authorization failures remain distinct typed errors. This package never changes Tailscale state.
12
+
13
+ `discoverFleetPeers` resolves every configured machine by its stable Tailscale node ID, then verifies the advertised hostname. Missing, duplicate, or hostname-mismatched identities fail closed; mutable hostname matches are never an authorization path. Offline machines remain present when their stable identity is still reported. `authorizeWhois` requires an allowed login and, when supplied, an allowed stable node ID.
@@ -0,0 +1,104 @@
1
+ import { Context, Effect, Layer, Schema } from "effect";
2
+ import { ChildProcessSpawner } from "effect/unstable/process";
3
+ export declare const TailIpv4: Schema.String;
4
+ export declare const TailIp: Schema.String;
5
+ export declare const TailNode: Schema.Struct<{
6
+ readonly DNSName: Schema.optionalKey<Schema.String>;
7
+ readonly HostName: Schema.String;
8
+ readonly ID: Schema.String;
9
+ readonly Online: Schema.Boolean;
10
+ readonly TailscaleIPs: Schema.$Array<Schema.String>;
11
+ }>;
12
+ export interface TailNode extends Schema.Schema.Type<typeof TailNode> {
13
+ }
14
+ export declare const TailStatus: Schema.Struct<{
15
+ readonly Peer: Schema.decodeTo<Schema.$Record<Schema.String, Schema.Struct<{
16
+ readonly DNSName: Schema.optionalKey<Schema.String>;
17
+ readonly HostName: Schema.String;
18
+ readonly ID: Schema.String;
19
+ readonly Online: Schema.Boolean;
20
+ readonly TailscaleIPs: Schema.$Array<Schema.String>;
21
+ }>>, Schema.NullOr<Schema.$Record<Schema.String, Schema.Struct<{
22
+ readonly DNSName: Schema.optionalKey<Schema.String>;
23
+ readonly HostName: Schema.String;
24
+ readonly ID: Schema.String;
25
+ readonly Online: Schema.Boolean;
26
+ readonly TailscaleIPs: Schema.$Array<Schema.String>;
27
+ }>>>, never, never>;
28
+ readonly Self: Schema.Struct<{
29
+ readonly DNSName: Schema.optionalKey<Schema.String>;
30
+ readonly HostName: Schema.String;
31
+ readonly ID: Schema.String;
32
+ readonly Online: Schema.Boolean;
33
+ readonly TailscaleIPs: Schema.$Array<Schema.String>;
34
+ }>;
35
+ }>;
36
+ export interface TailStatus extends Schema.Schema.Type<typeof TailStatus> {
37
+ }
38
+ export declare const TailWhois: Schema.Struct<{
39
+ readonly Node: Schema.Struct<{
40
+ readonly StableID: Schema.String;
41
+ }>;
42
+ readonly UserProfile: Schema.Struct<{
43
+ readonly LoginName: Schema.String;
44
+ }>;
45
+ }>;
46
+ export interface TailWhois extends Schema.Schema.Type<typeof TailWhois> {
47
+ }
48
+ export declare const FleetPeer: Schema.Struct<{
49
+ readonly host: Schema.String;
50
+ readonly ipv4: Schema.NullOr<Schema.String>;
51
+ readonly online: Schema.Boolean;
52
+ }>;
53
+ export interface FleetPeer extends Schema.Schema.Type<typeof FleetPeer> {
54
+ }
55
+ declare const TailscaleCommandError_base: Schema.Class<TailscaleCommandError, Schema.TaggedStruct<"HerdrTailscale.CommandError", {
56
+ readonly cause: Schema.Defect;
57
+ readonly operation: Schema.String;
58
+ }>, import("effect/Cause").YieldableError>;
59
+ export declare class TailscaleCommandError extends TailscaleCommandError_base {
60
+ }
61
+ declare const TailscaleDecodeError_base: Schema.Class<TailscaleDecodeError, Schema.TaggedStruct<"HerdrTailscale.DecodeError", {
62
+ readonly cause: Schema.Defect;
63
+ readonly operation: Schema.String;
64
+ }>, import("effect/Cause").YieldableError>;
65
+ export declare class TailscaleDecodeError extends TailscaleDecodeError_base {
66
+ }
67
+ declare const TailscaleAuthorizationError_base: Schema.Class<TailscaleAuthorizationError, Schema.TaggedStruct<"HerdrTailscale.AuthorizationError", {
68
+ readonly actor: Schema.String;
69
+ }>, import("effect/Cause").YieldableError>;
70
+ export declare class TailscaleAuthorizationError extends TailscaleAuthorizationError_base {
71
+ }
72
+ declare const TailscaleFleetIdentityError_base: Schema.Class<TailscaleFleetIdentityError, Schema.TaggedStruct<"HerdrTailscale.FleetIdentityError", {
73
+ readonly host: Schema.String;
74
+ readonly nodeId: Schema.String;
75
+ readonly reason: Schema.Literals<readonly ["duplicate", "host_mismatch", "missing"]>;
76
+ }>, import("effect/Cause").YieldableError>;
77
+ export declare class TailscaleFleetIdentityError extends TailscaleFleetIdentityError_base {
78
+ }
79
+ export interface ConfiguredFleetNode {
80
+ readonly host: string;
81
+ readonly nodeId: string;
82
+ }
83
+ export interface TailscaleClient {
84
+ readonly ipv4: Effect.Effect<string, TailscaleCommandError | TailscaleDecodeError>;
85
+ readonly status: Effect.Effect<TailStatus, TailscaleCommandError | TailscaleDecodeError>;
86
+ readonly whois: (address: string) => Effect.Effect<TailWhois, TailscaleCommandError | TailscaleDecodeError>;
87
+ }
88
+ declare const Tailscale_base: Context.ServiceClass<Tailscale, "@knpkv/herdr-tailscale/Tailscale", TailscaleClient>;
89
+ export declare class Tailscale extends Tailscale_base {
90
+ }
91
+ export declare const make: (executable: string) => Effect.Effect<TailscaleClient, never, ChildProcessSpawner.ChildProcessSpawner>;
92
+ export declare const layer: (executable: string) => Layer.Layer<Tailscale, never, ChildProcessSpawner.ChildProcessSpawner>;
93
+ export declare const nodeIpv4: (node: TailNode) => string | undefined;
94
+ export declare const resolveFleetNode: (status: TailStatus, machine: ConfiguredFleetNode) => Effect.Effect<{
95
+ readonly DNSName?: string;
96
+ readonly HostName: string;
97
+ readonly ID: string;
98
+ readonly Online: boolean;
99
+ readonly TailscaleIPs: readonly string[];
100
+ }, TailscaleFleetIdentityError, never>;
101
+ export declare const discoverFleetPeers: (localHost: string, machines: readonly ConfiguredFleetNode[]) => Effect.Effect<FleetPeer[], TailscaleCommandError | TailscaleDecodeError | TailscaleFleetIdentityError, Tailscale>;
102
+ export declare const authorizeWhois: (identity: TailWhois, allowedUsers: readonly string[], requiredNodeIds: readonly string[] | null) => Effect.Effect<string, TailscaleAuthorizationError, never>;
103
+ export {};
104
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAwB,MAAM,QAAQ,CAAA;AAC7E,OAAO,EAAgB,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAI3E,eAAO,MAAM,QAAQ,eAKpB,CAAA;AACD,eAAO,MAAM,MAAM,eAOlB,CAAA;AAED,eAAO,MAAM,QAAQ;;;;;;EAMnB,CAAA;AACF,MAAM,WAAW,QAAS,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC;CAAG;AASxE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;EAGrB,CAAA;AACF,MAAM,WAAW,UAAW,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC;CAAG;AAE5E,eAAO,MAAM,SAAS;;;;;;;EAGpB,CAAA;AACF,MAAM,WAAW,SAAU,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,SAAS,CAAC;CAAG;AAE1E,eAAO,MAAM,SAAS;;;;EAIpB,CAAA;AACF,MAAM,WAAW,SAAU,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,SAAS,CAAC;CAAG;;;;;AAE1E,qBAAa,qBAAsB,SAAQ,0BAG1C;CAAG;;;;;AAEJ,qBAAa,oBAAqB,SAAQ,yBAGzC;CAAG;;;;AAEJ,qBAAa,2BAA4B,SAAQ,gCAGhD;CAAG;;;;;;AAEJ,qBAAa,2BAA4B,SAAQ,gCAOhD;CAAG;AAEJ,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,GAAG,oBAAoB,CAAC,CAAA;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,GAAG,oBAAoB,CAAC,CAAA;IACxF,QAAQ,CAAC,KAAK,EAAE,CACd,OAAO,EAAE,MAAM,KACZ,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,qBAAqB,GAAG,oBAAoB,CAAC,CAAA;CAC5E;;AAOD,qBAAa,SAAU,SAAQ,cAE9B;CAAG;AA+EJ,eAAO,MAAM,IAAI,wGA4Bf,CAAA;AAEF,eAAO,MAAM,KAAK,eAAgB,MAAM,2EAA8C,CAAA;AAEtF,eAAO,MAAM,QAAQ,SAAU,QAAQ,KAAG,MAAM,GAAG,SAA2C,CAAA;AAE9F,eAAO,MAAM,gBAAgB;;;;;;sCA8B3B,CAAA;AAEF,eAAO,MAAM,kBAAkB,oLAmB7B,CAAA;AAEF,eAAO,MAAM,cAAc,gKAazB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,138 @@
1
+ import { Context, Effect, Layer, Schema, SchemaGetter, Stream } from "effect";
2
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
3
+ import { isIPv4, isIPv6 } from "node:net";
4
+ const BoundedName = Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(256));
5
+ export const TailIpv4 = Schema.String.check(Schema.makeFilter((address) => isIPv4(address) && address !== "0.0.0.0", { expected: "a specified IPv4 address" }));
6
+ export const TailIp = Schema.String.check(Schema.makeFilter((address) => (isIPv4(address) && address !== "0.0.0.0") ||
7
+ (isIPv6(address) && address !== "::"), { expected: "a specified IPv4 or IPv6 address" }));
8
+ export const TailNode = Schema.Struct({
9
+ DNSName: Schema.optionalKey(Schema.String),
10
+ HostName: BoundedName,
11
+ ID: BoundedName,
12
+ Online: Schema.Boolean,
13
+ TailscaleIPs: Schema.Array(TailIp)
14
+ });
15
+ const TailPeers = Schema.NullOr(Schema.Record(Schema.String, TailNode)).pipe(Schema.decodeTo(Schema.Record(Schema.String, TailNode), {
16
+ decode: SchemaGetter.transform((peers) => peers ?? {}),
17
+ encode: SchemaGetter.transform((peers) => peers)
18
+ }));
19
+ export const TailStatus = Schema.Struct({
20
+ Peer: TailPeers,
21
+ Self: TailNode
22
+ });
23
+ export const TailWhois = Schema.Struct({
24
+ Node: Schema.Struct({ StableID: BoundedName }),
25
+ UserProfile: Schema.Struct({ LoginName: BoundedName })
26
+ });
27
+ export const FleetPeer = Schema.Struct({
28
+ host: BoundedName,
29
+ ipv4: Schema.NullOr(TailIpv4),
30
+ online: Schema.Boolean
31
+ });
32
+ export class TailscaleCommandError extends Schema.TaggedError()("HerdrTailscale.CommandError", { cause: Schema.Defect(), operation: Schema.String }) {
33
+ }
34
+ export class TailscaleDecodeError extends Schema.TaggedError()("HerdrTailscale.DecodeError", { cause: Schema.Defect(), operation: Schema.String }) {
35
+ }
36
+ export class TailscaleAuthorizationError extends Schema.TaggedError()("HerdrTailscale.AuthorizationError", { actor: Schema.String }) {
37
+ }
38
+ export class TailscaleFleetIdentityError extends Schema.TaggedError()("HerdrTailscale.FleetIdentityError", {
39
+ host: BoundedName,
40
+ nodeId: BoundedName,
41
+ reason: Schema.Literals(["duplicate", "host_mismatch", "missing"])
42
+ }) {
43
+ }
44
+ export class Tailscale extends Context.Service()("@knpkv/herdr-tailscale/Tailscale") {
45
+ }
46
+ const decodeJson = (operation, schema, output) => Effect.try({
47
+ try: () => Schema.decodeUnknownSync(schema)(JSON.parse(output)),
48
+ catch: (cause) => new TailscaleDecodeError({ cause, operation })
49
+ });
50
+ const run = Effect.fn("HerdrTailscale.run")(function* (spawner, executable, operation, args) {
51
+ const collect = (stream) => stream.pipe(Stream.mapError((cause) => new TailscaleCommandError({ cause, operation })), Stream.runFoldEffect(() => ({ bytes: 0, chunks: [] }), (output, chunk) => {
52
+ const bytes = output.bytes + chunk.byteLength;
53
+ return bytes > 1024 * 1024
54
+ ? Effect.fail(new TailscaleCommandError({
55
+ cause: bytes,
56
+ operation: `${operation}.output_limit`
57
+ }))
58
+ : Effect.succeed({ bytes, chunks: [...output.chunks, chunk] });
59
+ }), Effect.flatMap((output) => Stream.fromIterable(output.chunks).pipe(Stream.decodeText(), Stream.mkString, Effect.mapError((cause) => new TailscaleCommandError({ cause, operation })))));
60
+ return yield* Effect.scoped(spawner.spawn(ChildProcess.make(executable, args)).pipe(Effect.mapError((cause) => new TailscaleCommandError({ cause, operation })), Effect.flatMap((handle) => Effect.all({
61
+ exitCode: handle.exitCode.pipe(Effect.mapError((cause) => new TailscaleCommandError({ cause, operation }))),
62
+ stderr: collect(handle.stderr),
63
+ stdout: collect(handle.stdout)
64
+ }, { concurrency: "unbounded" })), Effect.flatMap(({ exitCode, stderr, stdout }) => Number(exitCode) === 0
65
+ ? Effect.succeed(stdout)
66
+ : Effect.fail(new TailscaleCommandError({
67
+ cause: { exitCode, stderr },
68
+ operation
69
+ }))), Effect.timeoutOrElse({
70
+ duration: "10 seconds",
71
+ orElse: () => Effect.fail(new TailscaleCommandError({
72
+ cause: "10 seconds",
73
+ operation: `${operation}.timeout`
74
+ }))
75
+ })));
76
+ });
77
+ export const make = Effect.fn("HerdrTailscale.make")(function* (executable) {
78
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
79
+ const status = run(spawner, executable, "tailscale.status", ["status", "--json"]).pipe(Effect.flatMap((output) => decodeJson("tailscale.status.decode", TailStatus, output)));
80
+ const whois = Effect.fn("HerdrTailscale.whois")(function* (address) {
81
+ const output = yield* run(spawner, executable, "tailscale.whois", ["whois", "--json", address]);
82
+ return yield* decodeJson("tailscale.whois.decode", TailWhois, output);
83
+ });
84
+ const ipv4 = run(spawner, executable, "tailscale.ipv4", ["ip", "-4"]).pipe(Effect.map((output) => output.trim()), Effect.flatMap((address) => Schema.decodeUnknownEffect(TailIpv4)(address).pipe(Effect.mapError((cause) => new TailscaleDecodeError({
85
+ cause,
86
+ operation: "tailscale.ipv4"
87
+ })))));
88
+ return Tailscale.of({ ipv4, status, whois });
89
+ });
90
+ export const layer = (executable) => Layer.effect(Tailscale, make(executable));
91
+ export const nodeIpv4 = (node) => node.TailscaleIPs.find(isIPv4);
92
+ export const resolveFleetNode = Effect.fn("HerdrTailscale.resolveFleetNode")(function* (status, machine) {
93
+ const matches = [status.Self, ...Object.values(status.Peer)].filter(({ ID }) => ID === machine.nodeId);
94
+ const node = matches[0];
95
+ if (node === undefined) {
96
+ return yield* new TailscaleFleetIdentityError({
97
+ host: machine.host,
98
+ nodeId: machine.nodeId,
99
+ reason: "missing"
100
+ });
101
+ }
102
+ if (matches.length !== 1) {
103
+ return yield* new TailscaleFleetIdentityError({
104
+ host: machine.host,
105
+ nodeId: machine.nodeId,
106
+ reason: "duplicate"
107
+ });
108
+ }
109
+ if (node.HostName.toLowerCase() !== machine.host.toLowerCase()) {
110
+ return yield* new TailscaleFleetIdentityError({
111
+ host: machine.host,
112
+ nodeId: machine.nodeId,
113
+ reason: "host_mismatch"
114
+ });
115
+ }
116
+ return node;
117
+ });
118
+ export const discoverFleetPeers = Effect.fn("HerdrTailscale.discoverFleetPeers")(function* (localHost, machines) {
119
+ const tailscale = yield* Tailscale;
120
+ const status = yield* tailscale.status;
121
+ const resolved = yield* Effect.forEach(machines, (machine) => resolveFleetNode(status, machine).pipe(Effect.map((node) => ({
122
+ host: machine.host,
123
+ ipv4: nodeIpv4(node) ?? null,
124
+ online: node.Online
125
+ }))));
126
+ return resolved.filter(({ host }) => host.toLowerCase() !== localHost.toLowerCase());
127
+ });
128
+ export const authorizeWhois = Effect.fn("HerdrTailscale.authorizeWhois")(function* (identity, allowedUsers, requiredNodeIds) {
129
+ const login = identity.UserProfile.LoginName;
130
+ if (!allowedUsers.includes(login)) {
131
+ return yield* new TailscaleAuthorizationError({ actor: login });
132
+ }
133
+ if (requiredNodeIds !== null && !requiredNodeIds.includes(identity.Node.StableID)) {
134
+ return yield* new TailscaleAuthorizationError({ actor: identity.Node.StableID });
135
+ }
136
+ return login;
137
+ });
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@knpkv/herdr-tailscale",
3
+ "version": "0.2.0",
4
+ "description": "Effect adapter for authenticated Herdr fleet discovery over Tailscale",
5
+ "license": "MIT",
6
+ "author": "knpkv",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/knpkv/npm.git",
10
+ "directory": "packages/herdr-tailscale"
11
+ },
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "engines": {
30
+ "node": ">=26"
31
+ },
32
+ "dependencies": {
33
+ "effect": "4.0.0-rc.109"
34
+ },
35
+ "devDependencies": {
36
+ "@effect/platform-node": "4.0.0-rc.109",
37
+ "@effect/vitest": "4.0.0-rc.109",
38
+ "@types/node": "^26.2.0",
39
+ "rimraf": "^6.1.3",
40
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
41
+ "vitest": "^4.1.10"
42
+ },
43
+ "scripts": {
44
+ "build": "rimraf dist && tsc -b --force",
45
+ "check": "tsc -b tsconfig.json",
46
+ "clean": "rimraf dist *.tsbuildinfo",
47
+ "lint": "eslint \"{src,test}/**/*.ts\"",
48
+ "pack:deterministic": "pnpm build && node ../../scripts/pack-herdr.mjs .",
49
+ "test": "vitest run"
50
+ }
51
+ }