Fix Bifrost bridge runtime and fixture env isolation
This commit is contained in:
parent
0c53f70e25
commit
ba01b78d68
7 changed files with 147 additions and 15 deletions
|
|
@ -105,7 +105,7 @@ Each request has:
|
|||
|
||||
## CLI
|
||||
|
||||
`tools/agent-transport.mjs` is intentionally local and boring. It imports the sibling `CultCacheTS` and `CultNetTS` builds directly, writes a `.cc` store, and can emit/apply CultNet raw snapshots.
|
||||
`tools/agent-transport.mjs` is intentionally local and boring. It imports the local CultCache/CultNet TypeScript runtimes, preferring the current `CultLib\packages\cultcache-ts` and `CultLib\packages\cultnet-ts` packages while retaining the older sibling `CultCacheTS` / `CultNetTS` checkout paths as compatibility reliquaries. It writes a `.cc` store and can emit/apply CultNet raw snapshots.
|
||||
|
||||
Default store:
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,25 @@ console.log(JSON.stringify({
|
|||
Assert.Contains("BIFROST_BRIDGE_BASE_URL and BIFROST_BRIDGE_TOKEN", result.Stderr, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Agent_transport_fixture_harness_does_not_inherit_live_discord_mirror_env()
|
||||
{
|
||||
var storePath = Path.Combine(Path.GetTempPath(), $"bifrost-agent-transport-{Guid.NewGuid():N}.cc");
|
||||
var result = await RunNodeAsync([
|
||||
"tools/agent-transport.mjs",
|
||||
"enqueue",
|
||||
"--repo", "Bifrost",
|
||||
"--agent", "nibu",
|
||||
"--title", "Discord inheritance guard",
|
||||
"--request", "Do not post fixture noise.",
|
||||
"--store", storePath,
|
||||
"--allow-unreceipted-activity", "true",
|
||||
]);
|
||||
|
||||
Assert.NotEqual(0, result.ExitCode);
|
||||
Assert.Contains("require a Discord mirror", result.Stderr, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Agent_transport_mutation_allows_explicit_operator_recovery()
|
||||
{
|
||||
|
|
@ -982,6 +1001,8 @@ exit /b 0
|
|||
process.StartInfo.Environment["BIFROST_BRIDGE_TOKEN"] = string.Empty;
|
||||
process.StartInfo.Environment["BIFROST_ALLOW_UNGATED_GITHUB"] = string.Empty;
|
||||
process.StartInfo.Environment["BIFROST_ALLOW_UNRECEIPTED_ACTIVITY"] = string.Empty;
|
||||
process.StartInfo.Environment["BIFROST_SKIP_LOCAL_ENV"] = "true";
|
||||
ClearLiveDiscordMirrorEnvironment(process.StartInfo.Environment);
|
||||
if (environmentOverrides is not null)
|
||||
{
|
||||
foreach (var pair in environmentOverrides)
|
||||
|
|
@ -998,6 +1019,35 @@ exit /b 0
|
|||
return new ProcessResult(process.ExitCode, stdout, stderr);
|
||||
}
|
||||
|
||||
private static void ClearLiveDiscordMirrorEnvironment(IDictionary<string, string?> environment)
|
||||
{
|
||||
string[] exactKeys =
|
||||
[
|
||||
"BIFROST_ALLOW_UNMIRRORED_GOVERNANCE",
|
||||
"BIFROST_DISCORD_BOT_TOKEN",
|
||||
"BIFROST_DISCORD_CHANNEL_ID",
|
||||
"BIFROST_DISCORD_PERSONA_AVATAR_URL",
|
||||
"BIFROST_DISCORD_PERSONA_NAME",
|
||||
"DISCORD_BIFROST_CHANNEL_ID",
|
||||
"DISCORD_BOT_TOKEN",
|
||||
"DISCORD_PERSONA_AVATAR_URL",
|
||||
"DISCORD_PERSONA_AVATAR_URL_BIFROST",
|
||||
"DISCORD_PERSONA_WEBHOOK_URL",
|
||||
];
|
||||
|
||||
foreach (var key in exactKeys)
|
||||
{
|
||||
environment[key] = string.Empty;
|
||||
}
|
||||
|
||||
foreach (var key in environment.Keys
|
||||
.Where(key => key.StartsWith("BIFROST_DISCORD_PERSONA_WEBHOOK_URL_", StringComparison.OrdinalIgnoreCase))
|
||||
.ToArray())
|
||||
{
|
||||
environment[key] = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<ProcessResult> RunGitAsync(string[] args, string workingDirectory, IReadOnlyDictionary<string, string?>? environmentOverrides = null)
|
||||
=> await RunCommandAsync("git", args, workingDirectory, environmentOverrides);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,17 @@ const defaultPersonaName = "Bifrost";
|
|||
const defaultPersonaAvatarUrl =
|
||||
"https://raw.githubusercontent.com/GameCult/Bifrost/main/src/Bifrost.Web/wwwroot/img/bifrost-profile.png";
|
||||
|
||||
const cultCacheRequire = createRequire(resolve(projectsRoot, "CultCacheTS", "node_modules", "cultcache-ts", "package.json"));
|
||||
const cultNetRequire = createRequire(resolve(projectsRoot, "CultNetTS", "package.json"));
|
||||
const cultCachePackagePath = resolveFirstExisting("CultCache TypeScript runtime", [
|
||||
resolve(projectsRoot, "CultLib", "packages", "cultcache-ts", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "node_modules", "cultcache-ts", "package.json"),
|
||||
]);
|
||||
const cultNetPackagePath = resolveFirstExisting("CultNet TypeScript runtime", [
|
||||
resolve(projectsRoot, "CultLib", "packages", "cultnet-ts", "package.json"),
|
||||
resolve(projectsRoot, "CultNetTS", "package.json"),
|
||||
]);
|
||||
const cultCacheRequire = createRequire(cultCachePackagePath);
|
||||
const cultNetRequire = createRequire(cultNetPackagePath);
|
||||
|
||||
const {
|
||||
CultCache,
|
||||
|
|
@ -27,9 +36,19 @@ const {
|
|||
const {
|
||||
CultNetDocumentRegistry,
|
||||
defineCultNetDocumentBinding,
|
||||
} = cultNetRequire(resolve(projectsRoot, "CultNetTS", "dist", "index.js"));
|
||||
} = cultNetRequire("cultnet-ts");
|
||||
const { encode, decode } = cultNetRequire("@msgpack/msgpack");
|
||||
|
||||
function resolveFirstExisting(label, candidates) {
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`${label} is unavailable. Tried: ${candidates.join(", ")}`);
|
||||
}
|
||||
|
||||
const documentType = "bifrost.agent-transport.update-request";
|
||||
const schemaId = "bifrost.agent-transport.update-request.v0";
|
||||
const validStatuses = new Set(["queued", "claimed", "completed", "cancelled"]);
|
||||
|
|
@ -81,8 +100,7 @@ const cultNetRegistry = new CultNetDocumentRegistry([
|
|||
]);
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
loadBifrostLocalEnv();
|
||||
const [command, ...rawArgs] = process.argv.slice(2);
|
||||
const options = parseArgs(rawArgs);
|
||||
|
||||
|
|
@ -128,6 +146,15 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
function loadBifrostLocalEnv() {
|
||||
if (process.env.BIFROST_SKIP_LOCAL_ENV === "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
}
|
||||
|
||||
function isMutatingCommand(command) {
|
||||
return command === "enqueue"
|
||||
|| command === "claim"
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ const repoRoot = resolve(scriptDir, "..");
|
|||
const projectsRoot = resolve(repoRoot, "..");
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
loadBifrostLocalEnv();
|
||||
const [command, ...rawArgs] = process.argv.slice(2);
|
||||
const options = parseArgs(rawArgs);
|
||||
|
||||
|
|
@ -44,6 +43,15 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
function loadBifrostLocalEnv() {
|
||||
if (process.env.BIFROST_SKIP_LOCAL_ENV === "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
}
|
||||
|
||||
async function createGitHubDraftPr(options) {
|
||||
ensureGitHubBridgeGate(options);
|
||||
const repoRoot = resolve(requireOption(options, "repo-root"));
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ const defaultPersonaAvatarUrl =
|
|||
"https://raw.githubusercontent.com/GameCult/Bifrost/main/src/Bifrost.Web/wwwroot/img/bifrost-profile.png";
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv(resolve(bifrostRoot, ".env"));
|
||||
loadLocalEnv(resolve(defaultProjectsRoot, "VoidBot", ".env"));
|
||||
loadBifrostLocalEnv();
|
||||
const [command, ...rawArgs] = process.argv.slice(2);
|
||||
const options = parseArgs(rawArgs);
|
||||
|
||||
|
|
@ -43,6 +42,15 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
function loadBifrostLocalEnv() {
|
||||
if (process.env.BIFROST_SKIP_LOCAL_ENV === "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
loadLocalEnv(resolve(bifrostRoot, ".env"));
|
||||
loadLocalEnv(resolve(defaultProjectsRoot, "VoidBot", ".env"));
|
||||
}
|
||||
|
||||
async function dispatchQueuedRequests(options) {
|
||||
const max = parseInteger(options.max ?? "1", "max");
|
||||
const statusDir = resolveOptionPath(options["status-dir"] ?? defaultStatusDir);
|
||||
|
|
|
|||
|
|
@ -18,13 +18,28 @@ const defaultPersonaName = "Bifrost";
|
|||
const defaultPersonaAvatarUrl =
|
||||
"https://raw.githubusercontent.com/GameCult/Bifrost/main/src/Bifrost.Web/wwwroot/img/bifrost-profile.png";
|
||||
|
||||
const cultCacheRequire = createRequire(resolve(projectsRoot, "CultCacheTS", "node_modules", "cultcache-ts", "package.json"));
|
||||
const cultCachePackagePath = resolveFirstExisting("CultCache TypeScript runtime", [
|
||||
resolve(projectsRoot, "CultLib", "packages", "cultcache-ts", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "node_modules", "cultcache-ts", "package.json"),
|
||||
]);
|
||||
const cultCacheRequire = createRequire(cultCachePackagePath);
|
||||
const {
|
||||
CultCache,
|
||||
SingleFileMessagePackBackingStore,
|
||||
defineDocumentType,
|
||||
} = cultCacheRequire("cultcache-ts");
|
||||
|
||||
function resolveFirstExisting(label, candidates) {
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`${label} is unavailable. Tried: ${candidates.join(", ")}`);
|
||||
}
|
||||
|
||||
const topicType = "bifrost.governance.topic";
|
||||
const topicSchemaId = "bifrost.governance.topic.v0";
|
||||
const commentType = "bifrost.governance.topic-comment";
|
||||
|
|
@ -91,8 +106,7 @@ const commentDefinition = defineDocumentType({
|
|||
});
|
||||
|
||||
async function main() {
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
loadBifrostLocalEnv();
|
||||
const [command, ...rawArgs] = process.argv.slice(2);
|
||||
const options = parseArgs(rawArgs);
|
||||
|
||||
|
|
@ -138,6 +152,15 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
function loadBifrostLocalEnv() {
|
||||
if (process.env.BIFROST_SKIP_LOCAL_ENV === "true") {
|
||||
return;
|
||||
}
|
||||
|
||||
loadLocalEnv(resolve(repoRoot, ".env"));
|
||||
loadLocalEnv(resolve(projectsRoot, "VoidBot", ".env"));
|
||||
}
|
||||
|
||||
async function openCache(storePath) {
|
||||
const cache = CultCache.builder()
|
||||
.withDocumentType(topicDefinition)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const repoRoot = resolve(scriptDir, "..");
|
|||
const projectsRoot = resolve(repoRoot, "..");
|
||||
const defaultStorePath = resolve(repoRoot, ".bifrost", "provider-advertisement.cc");
|
||||
|
||||
const cultCacheRequire = createRequire(resolve(projectsRoot, "CultCacheTS", "package.json"));
|
||||
const cultCacheRequire = createRequire(resolveCultCachePackagePath());
|
||||
const cultCacheRuntime = loadCultCacheRuntime();
|
||||
const {
|
||||
CultCache,
|
||||
|
|
@ -21,8 +21,8 @@ const {
|
|||
|
||||
function loadCultCacheRuntime() {
|
||||
const candidates = [
|
||||
resolve(projectsRoot, "CultCacheTS", "dist", "index.js"),
|
||||
resolve(projectsRoot, "CultLib", "packages", "cultcache-ts", "dist", "index.js"),
|
||||
resolve(projectsRoot, "CultCacheTS", "dist", "index.js"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
|
|
@ -39,6 +39,22 @@ function loadCultCacheRuntime() {
|
|||
throw new Error("CultCache TypeScript runtime with document APIs is unavailable.");
|
||||
}
|
||||
|
||||
function resolveCultCachePackagePath() {
|
||||
const candidates = [
|
||||
resolve(projectsRoot, "CultLib", "packages", "cultcache-ts", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "package.json"),
|
||||
resolve(projectsRoot, "CultCacheTS", "node_modules", "cultcache-ts", "package.json"),
|
||||
];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`CultCache TypeScript runtime is unavailable. Tried: ${candidates.join(", ")}`);
|
||||
}
|
||||
|
||||
const documentType = "gamecult.eve.provider_advertisement";
|
||||
const schemaId = "gamecult.eve.provider_advertisement.v1";
|
||||
const documentId = "bifrost";
|
||||
|
|
|
|||
Loading…
Reference in a new issue