Skip to content
63 changes: 61 additions & 2 deletions apps/server/src/cli/policy.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import * as Console from "effect/Console";
import type { ManagedPolicyDocument } from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as References from "effect/References";
import { Argument, Command, GlobalFlag } from "effect/cli";
import { Argument, Command, Flag, GlobalFlag } from "effect/cli";
import * as CliError from "effect/cli/CliError";
import * as SecureRandom from "effect/crypto/SecureRandom";

import * as ManagedPolicy from "../policy/ManagedPolicy.ts";
import { macosProfile, windowsAdml, windowsAdmx } from "../policy/policyTemplates.ts";
import { isProcessAlive, readPersistedServerRuntimeState } from "../serverRuntimeState.ts";
import { projectLocationFlags, resolveCliAuthConfig } from "./config.ts";

Expand Down Expand Up @@ -103,7 +107,62 @@ const checkCommand = Command.make("check", {
),
);

const SAMPLE_POLICY: ManagedPolicyDocument = {
schemaVersion: 1,
organization: "Example Corp",
limits: { maxRuntimeMode: "auto-accept-edits", clients: ["desktop"], telemetry: false },
};

const templatesCommand = Command.make("templates", {
directory: Argument.String("directory").pipe(
Argument.withDescription("Directory to write the templates to."),
),
policy: Flag.String("policy").pipe(
Flag.withDescription("Policy file to put in the macOS profile. Default: a small sample."),
Flag.optional,
),
}).pipe(
Command.withDescription(
"Write the Windows Group Policy template and a macOS configuration profile.",
),
Command.withHandler(
Effect.fn("cli.policy.templates")(function* ({ directory, policy }) {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
let document = SAMPLE_POLICY;
if (Option.isSome(policy)) {
if (!(yield* fs.exists(policy.value))) {
return yield* new CliError.UserError({
cause: policy.value,
userMessage: `No policy file at ${policy.value}.`,
});
}
const loaded = (yield* ManagedPolicy.load(policy.value)).document;
if (loaded !== undefined) document = loaded;
}
const random = yield* SecureRandom.SecureRandom;
const profile = macosProfile(document, {
profile: yield* random.uuidV4().pipe(Effect.orDie),
payload: yield* random.uuidV4().pipe(Effect.orDie),
});
if (profile._tag === "Invalid") {
return yield* new CliError.UserError({ cause: document, userMessage: profile.reason });
}
const files = [
[path.join(directory, "windows", "t3code.admx"), windowsAdmx()],
[path.join(directory, "windows", "en-US", "t3code.adml"), windowsAdml()],
[path.join(directory, "macos", "t3code.mobileconfig"), profile.profile],
] as const;
for (const [file, contents] of files) {
yield* fs.makeDirectory(path.dirname(file), { recursive: true });
yield* fs.writeFileString(file, contents);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
yield* Console.log(file);
}
}),
),
);

export const policyCommand = Command.make("policy").pipe(
Command.withDescription("Inspect the administrator's managed policy."),
Command.withSubcommands([showCommand, checkCommand]),
Command.withSubcommands([showCommand, checkCommand, templatesCommand]),
);
5 changes: 4 additions & 1 deletion apps/server/src/policy/ManagedPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,10 @@ const make = Effect.gen(function* () {
const policy = yield* Option.match(devPath, {
onSome: load,
onNone: () =>
readManagedPolicy(platform).pipe(
readManagedPolicy(
platform,
ManagedProviders.knownDriverLabels().map(({ driver }) => driver),
).pipe(
Effect.flatMap((found) =>
fromDocument(found?.source ?? managedPolicyPath(platform), found?.document),
),
Expand Down
4 changes: 4 additions & 0 deletions apps/server/src/policy/managedProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ const KNOWN_DRIVERS: ReadonlyMap<ProviderDriverKind, KnownDriver> = new Map([
),
]);

/** Each driver a policy may name, with the label users see. */
export const knownDriverLabels = () =>
Array.from(KNOWN_DRIVERS, ([driver, { label }]) => ({ driver, label }));

const PINNED_CONFIG_FIELDS = ["binaryPath", "launchArgs"] as const;
type PinnedConfigField = (typeof PINNED_CONFIG_FIELDS)[number];

Expand Down
37 changes: 37 additions & 0 deletions apps/server/src/policy/policyTemplates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { assert, it } from "@effect/vitest";
import {
WINDOWS_POLICY_GROUPS,
WINDOWS_POLICY_LISTS,
WINDOWS_POLICY_VALUES,
} from "@t3tools/shared/managedPolicyFile";

import { macosProfile, windowsAdmx } from "./policyTemplates.ts";

it("gives every registry value the Windows reader accepts a Group Policy control", () => {
const admx = windowsAdmx();
for (const name of Object.keys(WINDOWS_POLICY_VALUES)) {
assert.include(admx, `valueName="${name}"`);
}
for (const key of Object.keys(WINDOWS_POLICY_LISTS)) {
assert.include(admx, `key="SOFTWARE\\Policies\\T3Tools\\T3Code\\${key}"`);
}
for (const name of Object.keys(WINDOWS_POLICY_GROUPS)) {
assert.include(admx, `valueName="${name}"`);
}
});

it("refuses a profile for a policy with a null value, which a plist cannot hold", () => {
const profile = macosProfile(
{
schemaVersion: 1,
organization: "Example Corp",
settings: { defaultModelSelection: { value: null, locked: true } },
},
{ profile: "profile-uuid", payload: "payload-uuid" },
);
assert.deepStrictEqual(profile, {
_tag: "Invalid",
reason:
"settings.defaultModelSelection is null, which a configuration profile cannot hold; deploy this policy as a file.",
});
});
Loading
Loading