@formthefog/stratus 2026.2.20 → 2026.3.19
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/.github/sentinel/action.yml +100 -0
- package/.github/sentinel/dist/codebase.d.ts +3 -0
- package/.github/sentinel/dist/codebase.d.ts.map +1 -0
- package/.github/sentinel/dist/context.d.ts +6 -0
- package/.github/sentinel/dist/context.d.ts.map +1 -0
- package/.github/sentinel/dist/fixer.d.ts +6 -0
- package/.github/sentinel/dist/fixer.d.ts.map +1 -0
- package/.github/sentinel/dist/index.d.ts +1 -0
- package/.github/sentinel/dist/index.d.ts.map +1 -0
- package/.github/sentinel/dist/index.js +68808 -0
- package/.github/sentinel/dist/index.js.map +1 -0
- package/.github/sentinel/dist/licenses.txt +1152 -0
- package/.github/sentinel/dist/models/anthropic.d.ts +26 -0
- package/.github/sentinel/dist/models/anthropic.d.ts.map +1 -0
- package/.github/sentinel/dist/models/openai.d.ts +26 -0
- package/.github/sentinel/dist/models/openai.d.ts.map +1 -0
- package/.github/sentinel/dist/models/openrouter.d.ts +31 -0
- package/.github/sentinel/dist/models/openrouter.d.ts.map +1 -0
- package/.github/sentinel/dist/models/types.d.ts +37 -0
- package/.github/sentinel/dist/models/types.d.ts.map +1 -0
- package/.github/sentinel/dist/orchestrator.d.ts +3 -0
- package/.github/sentinel/dist/orchestrator.d.ts.map +1 -0
- package/.github/sentinel/dist/policy.d.ts +15 -0
- package/.github/sentinel/dist/policy.d.ts.map +1 -0
- package/.github/sentinel/dist/reporter.d.ts +8 -0
- package/.github/sentinel/dist/reporter.d.ts.map +1 -0
- package/.github/sentinel/dist/responder.d.ts +6 -0
- package/.github/sentinel/dist/responder.d.ts.map +1 -0
- package/.github/sentinel/dist/router.d.ts +2 -0
- package/.github/sentinel/dist/router.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/config.d.ts +195 -0
- package/.github/sentinel/dist/schemas/config.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/fix.d.ts +130 -0
- package/.github/sentinel/dist/schemas/fix.d.ts.map +1 -0
- package/.github/sentinel/dist/schemas/review.d.ts +275 -0
- package/.github/sentinel/dist/schemas/review.d.ts.map +1 -0
- package/.github/sentinel/dist/sourcemap-register.js +1 -0
- package/.github/sentinel/dist/subway.d.ts +31 -0
- package/.github/sentinel/dist/subway.d.ts.map +1 -0
- package/.github/sentinel/dist/types.d.ts +210 -0
- package/.github/sentinel/dist/types.d.ts.map +1 -0
- package/.github/sentinel/package-lock.json +2389 -0
- package/.github/sentinel/package.json +29 -0
- package/.github/sentinel/src/codebase.ts +265 -0
- package/.github/sentinel/src/context.ts +182 -0
- package/.github/sentinel/src/fixer.ts +353 -0
- package/.github/sentinel/src/index.ts +263 -0
- package/.github/sentinel/src/models/anthropic.ts +244 -0
- package/.github/sentinel/src/models/openai.ts +242 -0
- package/.github/sentinel/src/models/openrouter.ts +319 -0
- package/.github/sentinel/src/models/types.ts +35 -0
- package/.github/sentinel/src/orchestrator.ts +287 -0
- package/.github/sentinel/src/policy.ts +133 -0
- package/.github/sentinel/src/reporter.ts +666 -0
- package/.github/sentinel/src/responder.ts +156 -0
- package/.github/sentinel/src/router.ts +308 -0
- package/.github/sentinel/src/schemas/config.ts +84 -0
- package/.github/sentinel/src/schemas/fix.ts +44 -0
- package/.github/sentinel/src/schemas/review.ts +73 -0
- package/.github/sentinel/src/subway.ts +250 -0
- package/.github/sentinel/src/types.ts +234 -0
- package/.github/sentinel/tsconfig.json +19 -0
- package/.github/sentinel.yml +34 -0
- package/.github/workflows/publish.yml +28 -0
- package/.github/workflows/sentinel.yml +55 -0
- package/README.md +90 -41
- package/SECURITY.md +85 -0
- package/TROUBLESHOOTING.md +2 -2
- package/index.ts +219 -109
- package/openclaw.plugin.json +50 -26
- package/package.json +1 -1
- package/skills/stratus-info/SKILL.md +70 -10
- package/src/client.ts +78 -18
- package/src/config.ts +29 -8
- package/src/setup.ts +53 -61
- package/src/types.ts +11 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as core from "@actions/core"
|
|
2
|
+
import * as github from "@actions/github"
|
|
3
|
+
import * as fs from "fs"
|
|
4
|
+
import { parse as parseYaml } from "yaml"
|
|
5
|
+
import { SentinelConfigSchema, type SentinelConfig } from "./schemas/config"
|
|
6
|
+
import type { RepoPolicies, ReviewMode, FindingSeverity, FixMode } from "./types"
|
|
7
|
+
|
|
8
|
+
type Octokit = ReturnType<typeof github.getOctokit>
|
|
9
|
+
|
|
10
|
+
export async function loadPolicies(
|
|
11
|
+
octokit: Octokit,
|
|
12
|
+
configPath: string,
|
|
13
|
+
modeOverride?: string
|
|
14
|
+
): Promise<RepoPolicies> {
|
|
15
|
+
const raw = await loadConfigFile(octokit, configPath)
|
|
16
|
+
const config = parseConfig(raw)
|
|
17
|
+
|
|
18
|
+
const mode = (modeOverride as ReviewMode) || config.mode
|
|
19
|
+
const anthropicModel = core.getInput("anthropic_model") || config.models.anthropic.model
|
|
20
|
+
const openaiModel = core.getInput("openai_model") || config.models.openai.model
|
|
21
|
+
const botNameInput = core.getInput("bot_name")
|
|
22
|
+
const fixModeInput = core.getInput("fix_mode")
|
|
23
|
+
const triggerLabelInput = core.getInput("trigger_label", { required: false, trimWhitespace: true })
|
|
24
|
+
const triggerLabelProvided = triggerLabelInput !== ""
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
mode,
|
|
28
|
+
autoFixEnabled: config.fix.mode !== "propose_only",
|
|
29
|
+
restrictedPaths: config.security.restricted_paths,
|
|
30
|
+
testCommands: config.validation.commands,
|
|
31
|
+
maxFiles: config.review.max_files,
|
|
32
|
+
maxPatchChars: config.review.max_patch_chars,
|
|
33
|
+
reviewRulesMarkdown: undefined,
|
|
34
|
+
architectureNotes: undefined,
|
|
35
|
+
severityThreshold: config.review.severity_threshold as FindingSeverity,
|
|
36
|
+
blockForkMutation: config.security.block_fork_mutation,
|
|
37
|
+
inlineComments: config.review.inline_comments,
|
|
38
|
+
commentStyle: config.review.comment_style,
|
|
39
|
+
models: {
|
|
40
|
+
anthropic: { enabled: config.models.anthropic.enabled, model: anthropicModel },
|
|
41
|
+
openai: { enabled: config.models.openai.enabled, model: openaiModel },
|
|
42
|
+
},
|
|
43
|
+
trigger: {
|
|
44
|
+
requireLabel: triggerLabelProvided ? triggerLabelInput : config.trigger.require_label,
|
|
45
|
+
respondToMentions: config.trigger.respond_to_mentions,
|
|
46
|
+
respondToReplies: config.trigger.respond_to_replies,
|
|
47
|
+
botName: botNameInput || config.trigger.bot_name,
|
|
48
|
+
},
|
|
49
|
+
fix: {
|
|
50
|
+
mode: (fixModeInput as FixMode) || config.fix.mode,
|
|
51
|
+
confidenceThreshold: config.fix.confidence_threshold,
|
|
52
|
+
createDraftPr: config.fix.create_draft_pr,
|
|
53
|
+
maxRetryCount: config.fix.max_retry_count,
|
|
54
|
+
},
|
|
55
|
+
review: {
|
|
56
|
+
summaryOnClean: config.review.summary_on_clean,
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function evaluateTrust(ctx: {
|
|
62
|
+
actor: string
|
|
63
|
+
isFork: boolean
|
|
64
|
+
policies: RepoPolicies
|
|
65
|
+
}): { trusted: boolean; canMutate: boolean; reason: string } {
|
|
66
|
+
if (ctx.isFork && ctx.policies.blockForkMutation) {
|
|
67
|
+
return { trusted: false, canMutate: false, reason: "Fork PR — mutation blocked by policy" }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (ctx.policies.mode === "manual_only") {
|
|
71
|
+
return { trusted: true, canMutate: false, reason: "Manual-only mode — review permitted, mutation requires command" }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return { trusted: true, canMutate: ctx.policies.autoFixEnabled, reason: "Trusted actor" }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function isRestrictedPath(filePath: string, patterns: string[]): boolean {
|
|
78
|
+
for (const pattern of patterns) {
|
|
79
|
+
if (matchGlob(filePath, pattern)) return true
|
|
80
|
+
}
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function loadConfigFile(
|
|
85
|
+
octokit: Octokit,
|
|
86
|
+
configPath: string
|
|
87
|
+
): Promise<Record<string, unknown> | null> {
|
|
88
|
+
if (fs.existsSync(configPath)) {
|
|
89
|
+
try {
|
|
90
|
+
const content = fs.readFileSync(configPath, "utf-8")
|
|
91
|
+
return parseYaml(content) as Record<string, unknown>
|
|
92
|
+
} catch (err) {
|
|
93
|
+
core.warning(`Failed to parse local config at ${configPath}: ${err}`)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const { owner, repo } = github.context.repo
|
|
99
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
100
|
+
owner,
|
|
101
|
+
repo,
|
|
102
|
+
path: configPath,
|
|
103
|
+
})
|
|
104
|
+
if ("content" in data && data.content) {
|
|
105
|
+
const decoded = Buffer.from(data.content, "base64").toString("utf-8")
|
|
106
|
+
return parseYaml(decoded) as Record<string, unknown>
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
109
|
+
core.info(`No config file found at ${configPath} — using defaults`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function parseConfig(raw: Record<string, unknown> | null): SentinelConfig {
|
|
116
|
+
if (!raw) return SentinelConfigSchema.parse({})
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
return SentinelConfigSchema.parse(raw)
|
|
120
|
+
} catch (err) {
|
|
121
|
+
core.warning(`Config validation failed, using defaults: ${err}`)
|
|
122
|
+
return SentinelConfigSchema.parse({})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function matchGlob(path: string, pattern: string): boolean {
|
|
127
|
+
const regex = pattern
|
|
128
|
+
.replace(/\./g, "\\.")
|
|
129
|
+
.replace(/\*\*/g, "{{GLOBSTAR}}")
|
|
130
|
+
.replace(/\*/g, "[^/]*")
|
|
131
|
+
.replace(/\{\{GLOBSTAR\}\}/g, ".*")
|
|
132
|
+
return new RegExp(`^${regex}$`).test(path)
|
|
133
|
+
}
|