evolcore 0.0.25 → 0.0.26
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 +607 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +160 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +50 -12
- package/dist/agents/codex/app-server-client.js +13 -5
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +121 -38
- package/dist/agents/ecagent-runner.js +4 -9
- package/dist/agents/gemini-runner.js +2 -7
- package/dist/agents/runner-types.js +25 -17
- package/dist/aun/aid/agentmd.js +81 -8
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/menu-client.js +74 -0
- package/dist/aun/msg/group.js +1 -1
- package/dist/aun/msg/managed-operation.js +1 -1
- package/dist/aun/msg/p2p.js +6 -1
- package/dist/aun/msg/upload.js +30 -22
- package/dist/channels/aun.js +329 -94
- package/dist/cli/agent-command.js +105 -84
- package/dist/cli/agent-create.js +112 -10
- package/dist/cli/agent.js +16 -5
- package/dist/cli/aun-commands.js +297 -296
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +47 -28
- package/dist/cli/contact.js +70 -13
- package/dist/cli/ctl-command.js +22 -22
- package/dist/cli/daemon-commands.js +105 -40
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +41 -9
- package/dist/cli/index.js +83 -77
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +46 -31
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +29 -29
- package/dist/cli/response.js +30 -30
- package/dist/cli/restart-monitor.js +87 -40
- package/dist/cli/stats.js +51 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-operation-service.js +145 -0
- package/dist/config/contact-operation-service.js +96 -7
- package/dist/config/resolved-config-op.js +27 -7
- package/dist/core/agent-application-service.js +2 -1
- package/dist/core/auth/authorization-audit.js +20 -12
- package/dist/core/auth/operation-authorizer.js +25 -4
- package/dist/core/auth/operation-catalog.js +35 -4
- package/dist/core/auth/remote-access-store.js +40 -1
- package/dist/core/bootstrap-service.js +1 -1
- package/dist/core/command/command-handler.js +83 -26
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/menu-catalog.js +12 -3
- package/dist/core/command/menu-handler.js +47 -26
- package/dist/core/command/menu-protocol.js +5 -0
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +86 -21
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/message/im-renderer.js +72 -21
- package/dist/core/message/message-bridge.js +69 -9
- package/dist/core/message/message-queue.js +26 -0
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +47 -28
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/ec-command-parser.js +51 -12
- package/dist/core/permission/sandbox-runtime.js +36 -14
- package/dist/core/permission/tool-policy.js +2 -1
- package/dist/index.js +280 -163
- package/dist/ipc.js +54 -2
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +21 -0
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +3 -1
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/welcome.js +22 -22
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +66 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +56 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +364 -364
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +71 -71
- package/kits/docs/evolcore/agent-create.md +170 -165
- package/kits/docs/evolcore/agent.md +66 -66
- package/kits/docs/evolcore/aid.md +60 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +202 -195
- package/kits/docs/evolcore/contact.md +75 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +243 -243
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +152 -152
- package/kits/docs/evolcore/menu-client.md +42 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +166 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +50 -50
- package/kits/docs/evolcore/trigger.md +575 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +269 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +37 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +190 -190
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +162 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +75 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +63 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +427 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +201 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +92 -92
- package/kits/templates/roles/member.json +96 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +85 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +31 -29
- package/kits/templates/system-fragments/channel.md +64 -64
- package/kits/templates/system-fragments/commands.md +28 -28
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +100 -98
|
@@ -1,160 +1,160 @@
|
|
|
1
|
-
param([Parameter(Mandatory = $true)][string]$Request)
|
|
2
|
-
|
|
3
|
-
# Called by the Node installer. Paths and security descriptors are data, never
|
|
4
|
-
# interpolated into PowerShell source. Use Windows PowerShell's built-in .NET ACL API.
|
|
5
|
-
$ErrorActionPreference = 'Stop'
|
|
6
|
-
$ProgressPreference = 'SilentlyContinue'
|
|
7
|
-
# A parent pwsh session can export its incompatible PowerShell 7 modules.
|
|
8
|
-
# This helper always runs in Windows PowerShell 5.1.
|
|
9
|
-
$env:PSModulePath = Join-Path $PSHOME 'Modules'
|
|
10
|
-
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
|
|
11
|
-
|
|
12
|
-
function Get-Descriptor([string]$Target) {
|
|
13
|
-
return (Get-Acl -LiteralPath $Target).GetSecurityDescriptorSddlForm(
|
|
14
|
-
[Security.AccessControl.AccessControlSections]'Access,Owner,Group')
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function Set-Descriptor([string]$Target, [string]$Sddl) {
|
|
18
|
-
$acl = Get-Acl -LiteralPath $Target
|
|
19
|
-
$acl.SetSecurityDescriptorSddlForm($Sddl, [Security.AccessControl.AccessControlSections]'Access,Owner,Group')
|
|
20
|
-
Set-Acl -LiteralPath $Target -AclObject $acl
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function Add-Grant($Acl, [string]$Sid, [Security.AccessControl.FileSystemRights]$Rights, [bool]$Directory) {
|
|
24
|
-
$inheritance = if ($Directory) { [Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit' } else { [Security.AccessControl.InheritanceFlags]::None }
|
|
25
|
-
$rule = New-Object Security.AccessControl.FileSystemAccessRule(
|
|
26
|
-
(New-Object Security.Principal.SecurityIdentifier($Sid)), $Rights, $inheritance,
|
|
27
|
-
[Security.AccessControl.PropagationFlags]::None, [Security.AccessControl.AccessControlType]::Allow)
|
|
28
|
-
$Acl.AddAccessRule($rule)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function Initialize-AccessProbe {
|
|
32
|
-
# An elevated process reading the file is not evidence that a normal process
|
|
33
|
-
# can read it. Evaluate the DACL with its UAC linked token when available.
|
|
34
|
-
Add-Type -TypeDefinition @'
|
|
35
|
-
using System;
|
|
36
|
-
using System.Runtime.InteropServices;
|
|
37
|
-
using System.Security.Principal;
|
|
38
|
-
public static class EvolCoreAclProbe {
|
|
39
|
-
[StructLayout(LayoutKind.Sequential)]
|
|
40
|
-
struct Mapping { public uint Read, Write, Execute, All; }
|
|
41
|
-
[DllImport("advapi32.dll", SetLastError=true)]
|
|
42
|
-
static extern bool GetTokenInformation(IntPtr token, int type, out IntPtr linked, int size, out int returned);
|
|
43
|
-
[DllImport("advapi32.dll", SetLastError=true)]
|
|
44
|
-
static extern bool DuplicateTokenEx(IntPtr token, uint desiredAccess, IntPtr tokenAttributes,
|
|
45
|
-
int impersonationLevel, int tokenType, out IntPtr duplicate);
|
|
46
|
-
[DllImport("advapi32.dll", SetLastError=true)]
|
|
47
|
-
static extern bool AccessCheck(byte[] descriptor, IntPtr token, uint desired,
|
|
48
|
-
ref Mapping mapping, byte[] privileges, ref uint length, out uint granted, out bool allowed);
|
|
49
|
-
[DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr handle);
|
|
50
|
-
public static string TokenKind;
|
|
51
|
-
public static long Granted(byte[] descriptor) {
|
|
52
|
-
using (var identity = WindowsIdentity.GetCurrent()) {
|
|
53
|
-
var principal = new WindowsPrincipal(identity);
|
|
54
|
-
IntPtr token = identity.Token, linked = IntPtr.Zero, duplicate = IntPtr.Zero;
|
|
55
|
-
try {
|
|
56
|
-
if (identity.IsSystem || principal.IsInRole(WindowsBuiltInRole.Administrator)) {
|
|
57
|
-
int size;
|
|
58
|
-
if (!GetTokenInformation(token, 19, out linked, IntPtr.Size, out size)) {
|
|
59
|
-
TokenKind = "unavailable";
|
|
60
|
-
return -1;
|
|
61
|
-
}
|
|
62
|
-
token = linked;
|
|
63
|
-
TokenKind = "linked-token";
|
|
64
|
-
} else { TokenKind = "current-token"; }
|
|
65
|
-
// AccessCheck only needs SecurityIdentification (1). A UAC linked
|
|
66
|
-
// token can be limited to that level, so requesting the higher
|
|
67
|
-
// SecurityImpersonation level fails with ERROR_BAD_IMPERSONATION_LEVEL.
|
|
68
|
-
if (!DuplicateTokenEx(token, 0x0000000A, IntPtr.Zero, 1, 2, out duplicate))
|
|
69
|
-
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
|
70
|
-
var mapping = new Mapping { Read=0x120089, Write=0x120116, Execute=0x1200a0, All=0x1f01ff };
|
|
71
|
-
uint length=1024, granted;
|
|
72
|
-
bool allowed;
|
|
73
|
-
if (!AccessCheck(descriptor, duplicate, 0x02000000, ref mapping,
|
|
74
|
-
new byte[length], ref length, out granted, out allowed))
|
|
75
|
-
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
|
76
|
-
return allowed ? granted : 0;
|
|
77
|
-
} finally {
|
|
78
|
-
if (duplicate != IntPtr.Zero) CloseHandle(duplicate);
|
|
79
|
-
if (linked != IntPtr.Zero) CloseHandle(linked);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
'@
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function Verify-Access($Entry) {
|
|
88
|
-
$target = [string]$Entry.path
|
|
89
|
-
$acl = Get-Acl -LiteralPath $target
|
|
90
|
-
$read = [long][Security.AccessControl.FileSystemRights]::ReadAndExecute
|
|
91
|
-
$write = [long][Security.AccessControl.FileSystemRights]'Write,Delete,DeleteSubdirectoriesAndFiles,ChangePermissions,TakeOwnership'
|
|
92
|
-
if ($Entry.protected) {
|
|
93
|
-
$grants = @{}
|
|
94
|
-
foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
95
|
-
if (($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -ne 0) { continue }
|
|
96
|
-
$sid = $rule.IdentityReference.Value
|
|
97
|
-
$rights = [long]$rule.FileSystemRights
|
|
98
|
-
if ($sid -in @('S-1-1-0','S-1-5-11','S-1-5-32-545')) {
|
|
99
|
-
if ($rule.AccessControlType -eq 'Allow' -and ($rights -band $write) -ne 0) {
|
|
100
|
-
throw "Unsafe write permission on ${target}: $sid has $($rule.FileSystemRights). Existing policy was not removed."
|
|
101
|
-
}
|
|
102
|
-
if ($rule.AccessControlType -eq 'Deny' -and ($rights -band $read) -ne 0) {
|
|
103
|
-
throw "Read permission denied on ${target}: $sid. Existing policy was not removed."
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if ($rule.AccessControlType -eq 'Allow') { $grants[$sid] = ([long]$grants[$sid]) -bor $rights }
|
|
107
|
-
}
|
|
108
|
-
foreach ($sid in @('S-1-5-18','S-1-5-32-544','S-1-5-32-545')) {
|
|
109
|
-
$required = if ($sid -eq 'S-1-5-32-545') { $read } else { [long][Security.AccessControl.FileSystemRights]::FullControl }
|
|
110
|
-
if ((([long]$grants[$sid]) -band $required) -ne $required) { throw "Missing required access on ${target}: $sid" }
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
$granted = [EvolCoreAclProbe]::Granted($acl.GetSecurityDescriptorBinaryForm())
|
|
114
|
-
if ($granted -ge 0) {
|
|
115
|
-
$required = if ($Entry.execute) { $read } else { [long][Security.AccessControl.FileSystemRights]::Read }
|
|
116
|
-
if (($granted -band $required) -ne $required) { throw "Normal-token read/execute access denied: $target" }
|
|
117
|
-
if ($Entry.protected -and ($granted -band $write) -ne 0) { throw "Normal token can modify the protected file or its ACL: $target" }
|
|
118
|
-
}
|
|
119
|
-
return @{ path = $target; userProbe = [EvolCoreAclProbe]::TokenKind }
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
$payload = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Request)) | ConvertFrom-Json
|
|
124
|
-
$result = switch ($payload.action) {
|
|
125
|
-
'preflight' {
|
|
126
|
-
$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
|
127
|
-
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
128
|
-
throw 'Machine-wide Codex hook provisioning requires an elevated Windows installer. npm installation does not require this step.'
|
|
129
|
-
}
|
|
130
|
-
@{ elevated = $true }
|
|
131
|
-
}
|
|
132
|
-
'snapshot' { @{ sddl = (Get-Descriptor $payload.path) } }
|
|
133
|
-
'prepare' {
|
|
134
|
-
$target = [string]$payload.path
|
|
135
|
-
if ($payload.reference) {
|
|
136
|
-
# Same-directory staging preserves the shared configuration's owner,
|
|
137
|
-
# inherited policy and custom administrator ACEs. Never reset its ACL.
|
|
138
|
-
Set-Descriptor $target (Get-Descriptor $payload.reference)
|
|
139
|
-
} else {
|
|
140
|
-
$flags = if ($payload.directory) { 'OICI' } else { '' }
|
|
141
|
-
Set-Descriptor $target "O:BAG:BAD:P(A;${flags};FA;;;SY)(A;${flags};FA;;;BA)(A;${flags};FRFX;;;BU)"
|
|
142
|
-
}
|
|
143
|
-
$acl = Get-Acl -LiteralPath $target
|
|
144
|
-
Add-Grant $acl 'S-1-5-18' 'FullControl' ([bool]$payload.directory)
|
|
145
|
-
Add-Grant $acl 'S-1-5-32-544' 'FullControl' ([bool]$payload.directory)
|
|
146
|
-
Add-Grant $acl 'S-1-5-32-545' 'ReadAndExecute' ([bool]$payload.directory)
|
|
147
|
-
Set-Acl -LiteralPath $target -AclObject $acl
|
|
148
|
-
@{ prepared = $true }
|
|
149
|
-
}
|
|
150
|
-
'verify' {
|
|
151
|
-
Initialize-AccessProbe
|
|
152
|
-
@($payload.entries | ForEach-Object { Verify-Access $_ })
|
|
153
|
-
}
|
|
154
|
-
default { throw "Unknown ACL operation: $($payload.action)" }
|
|
155
|
-
}
|
|
156
|
-
ConvertTo-Json -InputObject $result -Depth 8 -Compress
|
|
157
|
-
} catch {
|
|
158
|
-
[Console]::Error.WriteLine("[evolcore] ACL $($payload.action) failed for $($payload.path): $($_.Exception.Message)")
|
|
159
|
-
exit 1
|
|
160
|
-
}
|
|
1
|
+
param([Parameter(Mandatory = $true)][string]$Request)
|
|
2
|
+
|
|
3
|
+
# Called by the Node installer. Paths and security descriptors are data, never
|
|
4
|
+
# interpolated into PowerShell source. Use Windows PowerShell's built-in .NET ACL API.
|
|
5
|
+
$ErrorActionPreference = 'Stop'
|
|
6
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
7
|
+
# A parent pwsh session can export its incompatible PowerShell 7 modules.
|
|
8
|
+
# This helper always runs in Windows PowerShell 5.1.
|
|
9
|
+
$env:PSModulePath = Join-Path $PSHOME 'Modules'
|
|
10
|
+
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
|
|
11
|
+
|
|
12
|
+
function Get-Descriptor([string]$Target) {
|
|
13
|
+
return (Get-Acl -LiteralPath $Target).GetSecurityDescriptorSddlForm(
|
|
14
|
+
[Security.AccessControl.AccessControlSections]'Access,Owner,Group')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function Set-Descriptor([string]$Target, [string]$Sddl) {
|
|
18
|
+
$acl = Get-Acl -LiteralPath $Target
|
|
19
|
+
$acl.SetSecurityDescriptorSddlForm($Sddl, [Security.AccessControl.AccessControlSections]'Access,Owner,Group')
|
|
20
|
+
Set-Acl -LiteralPath $Target -AclObject $acl
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Add-Grant($Acl, [string]$Sid, [Security.AccessControl.FileSystemRights]$Rights, [bool]$Directory) {
|
|
24
|
+
$inheritance = if ($Directory) { [Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit' } else { [Security.AccessControl.InheritanceFlags]::None }
|
|
25
|
+
$rule = New-Object Security.AccessControl.FileSystemAccessRule(
|
|
26
|
+
(New-Object Security.Principal.SecurityIdentifier($Sid)), $Rights, $inheritance,
|
|
27
|
+
[Security.AccessControl.PropagationFlags]::None, [Security.AccessControl.AccessControlType]::Allow)
|
|
28
|
+
$Acl.AddAccessRule($rule)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Initialize-AccessProbe {
|
|
32
|
+
# An elevated process reading the file is not evidence that a normal process
|
|
33
|
+
# can read it. Evaluate the DACL with its UAC linked token when available.
|
|
34
|
+
Add-Type -TypeDefinition @'
|
|
35
|
+
using System;
|
|
36
|
+
using System.Runtime.InteropServices;
|
|
37
|
+
using System.Security.Principal;
|
|
38
|
+
public static class EvolCoreAclProbe {
|
|
39
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
40
|
+
struct Mapping { public uint Read, Write, Execute, All; }
|
|
41
|
+
[DllImport("advapi32.dll", SetLastError=true)]
|
|
42
|
+
static extern bool GetTokenInformation(IntPtr token, int type, out IntPtr linked, int size, out int returned);
|
|
43
|
+
[DllImport("advapi32.dll", SetLastError=true)]
|
|
44
|
+
static extern bool DuplicateTokenEx(IntPtr token, uint desiredAccess, IntPtr tokenAttributes,
|
|
45
|
+
int impersonationLevel, int tokenType, out IntPtr duplicate);
|
|
46
|
+
[DllImport("advapi32.dll", SetLastError=true)]
|
|
47
|
+
static extern bool AccessCheck(byte[] descriptor, IntPtr token, uint desired,
|
|
48
|
+
ref Mapping mapping, byte[] privileges, ref uint length, out uint granted, out bool allowed);
|
|
49
|
+
[DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr handle);
|
|
50
|
+
public static string TokenKind;
|
|
51
|
+
public static long Granted(byte[] descriptor) {
|
|
52
|
+
using (var identity = WindowsIdentity.GetCurrent()) {
|
|
53
|
+
var principal = new WindowsPrincipal(identity);
|
|
54
|
+
IntPtr token = identity.Token, linked = IntPtr.Zero, duplicate = IntPtr.Zero;
|
|
55
|
+
try {
|
|
56
|
+
if (identity.IsSystem || principal.IsInRole(WindowsBuiltInRole.Administrator)) {
|
|
57
|
+
int size;
|
|
58
|
+
if (!GetTokenInformation(token, 19, out linked, IntPtr.Size, out size)) {
|
|
59
|
+
TokenKind = "unavailable";
|
|
60
|
+
return -1;
|
|
61
|
+
}
|
|
62
|
+
token = linked;
|
|
63
|
+
TokenKind = "linked-token";
|
|
64
|
+
} else { TokenKind = "current-token"; }
|
|
65
|
+
// AccessCheck only needs SecurityIdentification (1). A UAC linked
|
|
66
|
+
// token can be limited to that level, so requesting the higher
|
|
67
|
+
// SecurityImpersonation level fails with ERROR_BAD_IMPERSONATION_LEVEL.
|
|
68
|
+
if (!DuplicateTokenEx(token, 0x0000000A, IntPtr.Zero, 1, 2, out duplicate))
|
|
69
|
+
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
|
70
|
+
var mapping = new Mapping { Read=0x120089, Write=0x120116, Execute=0x1200a0, All=0x1f01ff };
|
|
71
|
+
uint length=1024, granted;
|
|
72
|
+
bool allowed;
|
|
73
|
+
if (!AccessCheck(descriptor, duplicate, 0x02000000, ref mapping,
|
|
74
|
+
new byte[length], ref length, out granted, out allowed))
|
|
75
|
+
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
|
|
76
|
+
return allowed ? granted : 0;
|
|
77
|
+
} finally {
|
|
78
|
+
if (duplicate != IntPtr.Zero) CloseHandle(duplicate);
|
|
79
|
+
if (linked != IntPtr.Zero) CloseHandle(linked);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
'@
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function Verify-Access($Entry) {
|
|
88
|
+
$target = [string]$Entry.path
|
|
89
|
+
$acl = Get-Acl -LiteralPath $target
|
|
90
|
+
$read = [long][Security.AccessControl.FileSystemRights]::ReadAndExecute
|
|
91
|
+
$write = [long][Security.AccessControl.FileSystemRights]'Write,Delete,DeleteSubdirectoriesAndFiles,ChangePermissions,TakeOwnership'
|
|
92
|
+
if ($Entry.protected) {
|
|
93
|
+
$grants = @{}
|
|
94
|
+
foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
|
|
95
|
+
if (($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -ne 0) { continue }
|
|
96
|
+
$sid = $rule.IdentityReference.Value
|
|
97
|
+
$rights = [long]$rule.FileSystemRights
|
|
98
|
+
if ($sid -in @('S-1-1-0','S-1-5-11','S-1-5-32-545')) {
|
|
99
|
+
if ($rule.AccessControlType -eq 'Allow' -and ($rights -band $write) -ne 0) {
|
|
100
|
+
throw "Unsafe write permission on ${target}: $sid has $($rule.FileSystemRights). Existing policy was not removed."
|
|
101
|
+
}
|
|
102
|
+
if ($rule.AccessControlType -eq 'Deny' -and ($rights -band $read) -ne 0) {
|
|
103
|
+
throw "Read permission denied on ${target}: $sid. Existing policy was not removed."
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if ($rule.AccessControlType -eq 'Allow') { $grants[$sid] = ([long]$grants[$sid]) -bor $rights }
|
|
107
|
+
}
|
|
108
|
+
foreach ($sid in @('S-1-5-18','S-1-5-32-544','S-1-5-32-545')) {
|
|
109
|
+
$required = if ($sid -eq 'S-1-5-32-545') { $read } else { [long][Security.AccessControl.FileSystemRights]::FullControl }
|
|
110
|
+
if ((([long]$grants[$sid]) -band $required) -ne $required) { throw "Missing required access on ${target}: $sid" }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
$granted = [EvolCoreAclProbe]::Granted($acl.GetSecurityDescriptorBinaryForm())
|
|
114
|
+
if ($granted -ge 0) {
|
|
115
|
+
$required = if ($Entry.execute) { $read } else { [long][Security.AccessControl.FileSystemRights]::Read }
|
|
116
|
+
if (($granted -band $required) -ne $required) { throw "Normal-token read/execute access denied: $target" }
|
|
117
|
+
if ($Entry.protected -and ($granted -band $write) -ne 0) { throw "Normal token can modify the protected file or its ACL: $target" }
|
|
118
|
+
}
|
|
119
|
+
return @{ path = $target; userProbe = [EvolCoreAclProbe]::TokenKind }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
$payload = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Request)) | ConvertFrom-Json
|
|
124
|
+
$result = switch ($payload.action) {
|
|
125
|
+
'preflight' {
|
|
126
|
+
$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
|
127
|
+
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
128
|
+
throw 'Machine-wide Codex hook provisioning requires an elevated Windows installer. npm installation does not require this step.'
|
|
129
|
+
}
|
|
130
|
+
@{ elevated = $true }
|
|
131
|
+
}
|
|
132
|
+
'snapshot' { @{ sddl = (Get-Descriptor $payload.path) } }
|
|
133
|
+
'prepare' {
|
|
134
|
+
$target = [string]$payload.path
|
|
135
|
+
if ($payload.reference) {
|
|
136
|
+
# Same-directory staging preserves the shared configuration's owner,
|
|
137
|
+
# inherited policy and custom administrator ACEs. Never reset its ACL.
|
|
138
|
+
Set-Descriptor $target (Get-Descriptor $payload.reference)
|
|
139
|
+
} else {
|
|
140
|
+
$flags = if ($payload.directory) { 'OICI' } else { '' }
|
|
141
|
+
Set-Descriptor $target "O:BAG:BAD:P(A;${flags};FA;;;SY)(A;${flags};FA;;;BA)(A;${flags};FRFX;;;BU)"
|
|
142
|
+
}
|
|
143
|
+
$acl = Get-Acl -LiteralPath $target
|
|
144
|
+
Add-Grant $acl 'S-1-5-18' 'FullControl' ([bool]$payload.directory)
|
|
145
|
+
Add-Grant $acl 'S-1-5-32-544' 'FullControl' ([bool]$payload.directory)
|
|
146
|
+
Add-Grant $acl 'S-1-5-32-545' 'ReadAndExecute' ([bool]$payload.directory)
|
|
147
|
+
Set-Acl -LiteralPath $target -AclObject $acl
|
|
148
|
+
@{ prepared = $true }
|
|
149
|
+
}
|
|
150
|
+
'verify' {
|
|
151
|
+
Initialize-AccessProbe
|
|
152
|
+
@($payload.entries | ForEach-Object { Verify-Access $_ })
|
|
153
|
+
}
|
|
154
|
+
default { throw "Unknown ACL operation: $($payload.action)" }
|
|
155
|
+
}
|
|
156
|
+
ConvertTo-Json -InputObject $result -Depth 8 -Compress
|
|
157
|
+
} catch {
|
|
158
|
+
[Console]::Error.WriteLine("[evolcore] ACL $($payload.action) failed for $($payload.path): $($_.Exception.Message)")
|
|
159
|
+
exit 1
|
|
160
|
+
}
|