Gate public bridge actions on Bifrost identity
This commit is contained in:
parent
c533a7f98c
commit
445c27978b
9 changed files with 325 additions and 0 deletions
|
|
@ -79,6 +79,7 @@ For the full staged roadmap, including contribution points, revenue share, patro
|
|||
- GitHub bridge actions that claim Bifrost-owned provenance now validate that provenance too: a `bifrost_agent_transport_request` source must point at a known request-lane request for the same repo, and governance-backed bridge actions must point at a known Bifrost topic instead of a decorative source string
|
||||
- governance-backed GitHub publication is also no longer allowed to jump the queue: a Bifrost governance topic must have been approved or promoted before it can justify a GitHub bridge action
|
||||
- non-GitHub bridge activity is no longer allowed to drift off-book either: `discord-post`, `discord-dm`, and `reddit-post` now require `BIFROST_BRIDGE_BASE_URL` and `BIFROST_BRIDGE_TOKEN` by default, with `--allow-unreceipted-activity true` reserved for explicit local recovery and refused inside dispatched work
|
||||
- Persona and agent `discord-post` / `reddit-post` bridge actions also require a Bifrost identity plus Heimdall-backed capability/account reference in the hosted ledger; pass `--identity`, `--heimdall-capability-ref`, and the Epiphany provenance flags or set the matching environment variables. The bridge token is an actuator credential, not identity or provider authority.
|
||||
- Bifrost-dispatched Codex turns also inject Bifrost-owned GitHub gates through environment config: `git` and `gh` wrappers are prepended in `PATH`, a `pre-push` hook backs up raw Git pushes, raw `git push` stays blocked, and direct `gh` usage is limited to explicit read-only commands unless `tools/bifrost-bridge.mjs` authorizes the bridge-owned GitHub write path
|
||||
- dispatched Codex turns now default to `workspace-write` instead of full machine access, and the app-server sandbox policy disables network access unless the operator explicitly chooses a broader sandbox
|
||||
- `tools/agent-transport.mjs` also uses that bridge configuration to record `/transport/receipts` entries for queue, claim, release, and close events on the request lane
|
||||
|
|
|
|||
|
|
@ -58,6 +58,13 @@ The hosted app now exposes a first-class bridge action ledger for governed trans
|
|||
- `POST /bridge/actions/{id}/fail`
|
||||
|
||||
The owner is Bifrost, not the local script. The script or agent may execute the crossing, but Bifrost records the request, policy decision, lifecycle state, and receipt.
|
||||
Persona and agent actions that cross into Discord or Reddit must carry a Bifrost
|
||||
identity plus a Heimdall-backed capability/account reference at request time.
|
||||
The local bridge token only proves that the actuator may call the ledger; it is
|
||||
not the actor identity and not outside-provider authority. The ledger stores the
|
||||
Bifrost identity, Heimdall reference, Epiphany run id, lane id, and agent
|
||||
identity beside the action so later receipts can answer which agent did what
|
||||
without opening local transcripts or trusting helper-script folklore.
|
||||
|
||||
The hosted app also exposes a dispatch-run ledger for the older Bifrost-launched worker bridge:
|
||||
|
||||
|
|
|
|||
|
|
@ -415,6 +415,11 @@ public sealed class BifrostDbContext(DbContextOptions<BifrostDbContext> options)
|
|||
entity.Property(x => x.SourceKind).HasMaxLength(120);
|
||||
entity.Property(x => x.SourceId).HasMaxLength(240);
|
||||
entity.Property(x => x.AuthorityReference).HasMaxLength(240);
|
||||
entity.Property(x => x.BifrostIdentity).HasMaxLength(160);
|
||||
entity.Property(x => x.HeimdallCapabilityReference).HasMaxLength(240);
|
||||
entity.Property(x => x.EpiphanyRunId).HasMaxLength(160);
|
||||
entity.Property(x => x.EpiphanyLaneId).HasMaxLength(120);
|
||||
entity.Property(x => x.EpiphanyAgentIdentity).HasMaxLength(160);
|
||||
entity.Property(x => x.PolicyDecision).HasMaxLength(500);
|
||||
entity.Property(x => x.Title).HasMaxLength(240);
|
||||
entity.Property(x => x.ReceiptUrl).HasMaxLength(500);
|
||||
|
|
@ -423,6 +428,8 @@ public sealed class BifrostDbContext(DbContextOptions<BifrostDbContext> options)
|
|||
entity.HasIndex(x => new { x.TargetSurface, x.ActionKind, x.Status });
|
||||
entity.HasIndex(x => new { x.ActorKind, x.ActorName });
|
||||
entity.HasIndex(x => new { x.SourceKind, x.SourceId });
|
||||
entity.HasIndex(x => x.BifrostIdentity);
|
||||
entity.HasIndex(x => x.HeimdallCapabilityReference);
|
||||
entity.HasOne(x => x.ActorUserAccount)
|
||||
.WithMany(x => x.BridgeActions)
|
||||
.HasForeignKey(x => x.ActorUserAccountId)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Bifrost.Web.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddBridgeActionIdentityProvenance : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "BifrostIdentity",
|
||||
table: "BridgeActions",
|
||||
type: "character varying(160)",
|
||||
maxLength: 160,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "EpiphanyAgentIdentity",
|
||||
table: "BridgeActions",
|
||||
type: "character varying(160)",
|
||||
maxLength: 160,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "EpiphanyLaneId",
|
||||
table: "BridgeActions",
|
||||
type: "character varying(120)",
|
||||
maxLength: 120,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "EpiphanyRunId",
|
||||
table: "BridgeActions",
|
||||
type: "character varying(160)",
|
||||
maxLength: 160,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "HeimdallCapabilityReference",
|
||||
table: "BridgeActions",
|
||||
type: "character varying(240)",
|
||||
maxLength: 240,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BridgeActions_BifrostIdentity",
|
||||
table: "BridgeActions",
|
||||
column: "BifrostIdentity");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BridgeActions_HeimdallCapabilityReference",
|
||||
table: "BridgeActions",
|
||||
column: "HeimdallCapabilityReference");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BridgeActions_BifrostIdentity",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BridgeActions_HeimdallCapabilityReference",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BifrostIdentity",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EpiphanyAgentIdentity",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EpiphanyLaneId",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "EpiphanyRunId",
|
||||
table: "BridgeActions");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "HeimdallCapabilityReference",
|
||||
table: "BridgeActions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -279,9 +279,29 @@ namespace Bifrost.Web.Data.Migrations
|
|||
.HasMaxLength(240)
|
||||
.HasColumnType("character varying(240)");
|
||||
|
||||
b.Property<string>("BifrostIdentity")
|
||||
.IsRequired()
|
||||
.HasMaxLength(160)
|
||||
.HasColumnType("character varying(160)");
|
||||
|
||||
b.Property<DateTimeOffset?>("CompletedAtUtc")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("EpiphanyAgentIdentity")
|
||||
.IsRequired()
|
||||
.HasMaxLength(160)
|
||||
.HasColumnType("character varying(160)");
|
||||
|
||||
b.Property<string>("EpiphanyLaneId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(120)
|
||||
.HasColumnType("character varying(120)");
|
||||
|
||||
b.Property<string>("EpiphanyRunId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(160)
|
||||
.HasColumnType("character varying(160)");
|
||||
|
||||
b.Property<string>("ExternalReceiptId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(240)
|
||||
|
|
@ -291,6 +311,11 @@ namespace Bifrost.Web.Data.Migrations
|
|||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("HeimdallCapabilityReference")
|
||||
.IsRequired()
|
||||
.HasMaxLength(240)
|
||||
.HasColumnType("character varying(240)");
|
||||
|
||||
b.Property<Guid?>("MotionId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
|
|
@ -361,6 +386,10 @@ namespace Bifrost.Web.Data.Migrations
|
|||
|
||||
b.HasIndex("ActorUserAccountId");
|
||||
|
||||
b.HasIndex("BifrostIdentity");
|
||||
|
||||
b.HasIndex("HeimdallCapabilityReference");
|
||||
|
||||
b.HasIndex("MotionId");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
|
|
|||
|
|
@ -926,6 +926,16 @@ public sealed class BridgeAction
|
|||
|
||||
public string AuthorityReference { get; set; } = string.Empty;
|
||||
|
||||
public string BifrostIdentity { get; set; } = string.Empty;
|
||||
|
||||
public string HeimdallCapabilityReference { get; set; } = string.Empty;
|
||||
|
||||
public string EpiphanyRunId { get; set; } = string.Empty;
|
||||
|
||||
public string EpiphanyLaneId { get; set; } = string.Empty;
|
||||
|
||||
public string EpiphanyAgentIdentity { get; set; } = string.Empty;
|
||||
|
||||
public string PolicyDecision { get; set; } = string.Empty;
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@ public sealed class BridgeActionService(
|
|||
SourceKind = NormalizeText(normalizedRequest.SourceKind),
|
||||
SourceId = NormalizeText(normalizedRequest.SourceId),
|
||||
AuthorityReference = NormalizeText(normalizedRequest.AuthorityReference),
|
||||
BifrostIdentity = NormalizeText(normalizedRequest.BifrostIdentity),
|
||||
HeimdallCapabilityReference = NormalizeText(normalizedRequest.HeimdallCapabilityReference),
|
||||
EpiphanyRunId = NormalizeText(normalizedRequest.EpiphanyRunId),
|
||||
EpiphanyLaneId = NormalizeText(normalizedRequest.EpiphanyLaneId),
|
||||
EpiphanyAgentIdentity = NormalizeText(normalizedRequest.EpiphanyAgentIdentity),
|
||||
PolicyDecision = policy.Decision,
|
||||
Title = NormalizeText(normalizedRequest.Title),
|
||||
Summary = NormalizeText(normalizedRequest.Summary),
|
||||
|
|
@ -200,6 +205,19 @@ public sealed class BridgeActionService(
|
|||
}
|
||||
}
|
||||
|
||||
if (RequiresExternalAccountCapability(request))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(request.BifrostIdentity))
|
||||
{
|
||||
return BridgePolicyDecision.Reject("Persona and agent Discord/Reddit bridge actions must carry a Bifrost identity.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.HeimdallCapabilityReference))
|
||||
{
|
||||
return BridgePolicyDecision.Reject("Persona and agent Discord/Reddit bridge actions must carry a Heimdall-backed capability or account reference.");
|
||||
}
|
||||
}
|
||||
|
||||
if (request.WorkItemId is not null)
|
||||
{
|
||||
var workItem = await dbContext.WorkItems
|
||||
|
|
@ -350,6 +368,10 @@ public sealed class BridgeActionService(
|
|||
return null;
|
||||
}
|
||||
|
||||
private static bool RequiresExternalAccountCapability(BridgeActionRequest request) =>
|
||||
request.ActorKind is BridgeActorKind.Agent or BridgeActorKind.Persona &&
|
||||
request.TargetSurface is BridgeTargetSurface.Discord or BridgeTargetSurface.Reddit;
|
||||
|
||||
private static string NormalizeRepository(string value) => NormalizeText(value).ToLowerInvariant();
|
||||
|
||||
private static string ShortRepositoryName(string normalizedRepositoryFullName)
|
||||
|
|
@ -391,6 +413,11 @@ public sealed record BridgeActionRequest(
|
|||
string SourceKind,
|
||||
string SourceId,
|
||||
string AuthorityReference,
|
||||
string BifrostIdentity,
|
||||
string HeimdallCapabilityReference,
|
||||
string EpiphanyRunId,
|
||||
string EpiphanyLaneId,
|
||||
string EpiphanyAgentIdentity,
|
||||
string Title,
|
||||
string Summary,
|
||||
Guid? WorkItemId = null,
|
||||
|
|
@ -408,6 +435,11 @@ public sealed record BridgeActionRequest(
|
|||
SourceKind = NormalizeText(SourceKind),
|
||||
SourceId = NormalizeText(SourceId),
|
||||
AuthorityReference = NormalizeText(AuthorityReference),
|
||||
BifrostIdentity = NormalizeText(BifrostIdentity),
|
||||
HeimdallCapabilityReference = NormalizeText(HeimdallCapabilityReference),
|
||||
EpiphanyRunId = NormalizeText(EpiphanyRunId),
|
||||
EpiphanyLaneId = NormalizeText(EpiphanyLaneId),
|
||||
EpiphanyAgentIdentity = NormalizeText(EpiphanyAgentIdentity),
|
||||
Title = NormalizeText(Title),
|
||||
Summary = NormalizeText(Summary)
|
||||
};
|
||||
|
|
@ -434,6 +466,11 @@ public sealed record BridgeActionResult(
|
|||
string SourceKind,
|
||||
string SourceId,
|
||||
string AuthorityReference,
|
||||
string BifrostIdentity,
|
||||
string HeimdallCapabilityReference,
|
||||
string EpiphanyRunId,
|
||||
string EpiphanyLaneId,
|
||||
string EpiphanyAgentIdentity,
|
||||
string PolicyDecision,
|
||||
string Title,
|
||||
string ReceiptUrl,
|
||||
|
|
@ -453,6 +490,11 @@ public sealed record BridgeActionResult(
|
|||
action.SourceKind,
|
||||
action.SourceId,
|
||||
action.AuthorityReference,
|
||||
action.BifrostIdentity,
|
||||
action.HeimdallCapabilityReference,
|
||||
action.EpiphanyRunId,
|
||||
action.EpiphanyLaneId,
|
||||
action.EpiphanyAgentIdentity,
|
||||
action.PolicyDecision,
|
||||
action.Title,
|
||||
action.ReceiptUrl,
|
||||
|
|
|
|||
|
|
@ -702,6 +702,130 @@ public sealed class PlatformEndpointsTests : IClassFixture<TestWebApplicationFac
|
|||
Assert.Equal("Authorized", action.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Persona_reddit_action_without_bifrost_identity_or_heimdall_reference_is_denied()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
|
||||
var requestPayload = JsonSerializer.Serialize(new
|
||||
{
|
||||
actorKind = "Persona",
|
||||
actorName = "Epiphany Persona",
|
||||
targetSurface = "Reddit",
|
||||
actionKind = "RedditPost",
|
||||
targetLocator = "r/GameCultOrg",
|
||||
sourceKind = "epiphany_persona_reddit",
|
||||
sourceId = "persona-speech-audit-missing-identity",
|
||||
authorityReference = "epiphany.persona_speech_audit",
|
||||
title = "Persona Reddit thread",
|
||||
summary = "This should not pass without Bifrost identity plus Heimdall reference."
|
||||
});
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, "/bridge/actions/request");
|
||||
request.Headers.Add("X-Bifrost-Bridge-Token", "test-bridge-token");
|
||||
request.Content = new StringContent(requestPayload, Encoding.UTF8, "application/json");
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
var action = await response.Content.ReadFromJsonAsync<BridgeActionHttpResult>();
|
||||
Assert.NotNull(action);
|
||||
Assert.Equal("Denied", action.Status);
|
||||
|
||||
using var scope = _factory.Services.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<BifrostDbContext>();
|
||||
var savedAction = dbContext.BridgeActions.Single(x => x.Id == action.Id);
|
||||
|
||||
Assert.Equal(BridgeActionStatus.Denied, savedAction.Status);
|
||||
Assert.Contains("Bifrost identity", savedAction.PolicyDecision, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Persona_discord_action_requires_heimdall_reference_after_bifrost_identity()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
|
||||
var requestPayload = JsonSerializer.Serialize(new
|
||||
{
|
||||
actorKind = "Persona",
|
||||
actorName = "Epiphany Persona",
|
||||
targetSurface = "Discord",
|
||||
actionKind = "DiscordPost",
|
||||
targetLocator = "channel/1501196543150264332",
|
||||
sourceKind = "epiphany_persona_speech",
|
||||
sourceId = "persona-speech-audit-missing-heimdall",
|
||||
authorityReference = "epiphany.persona_speech_audit",
|
||||
bifrostIdentity = "epiphany.Persona",
|
||||
title = "Persona Discord post",
|
||||
summary = "This should not pass without an outside-account capability reference."
|
||||
});
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, "/bridge/actions/request");
|
||||
request.Headers.Add("X-Bifrost-Bridge-Token", "test-bridge-token");
|
||||
request.Content = new StringContent(requestPayload, Encoding.UTF8, "application/json");
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
|
||||
var action = await response.Content.ReadFromJsonAsync<BridgeActionHttpResult>();
|
||||
Assert.NotNull(action);
|
||||
Assert.Equal("Denied", action.Status);
|
||||
|
||||
using var scope = _factory.Services.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<BifrostDbContext>();
|
||||
var savedAction = dbContext.BridgeActions.Single(x => x.Id == action.Id);
|
||||
|
||||
Assert.Equal(BridgeActionStatus.Denied, savedAction.Status);
|
||||
Assert.Contains("Heimdall", savedAction.PolicyDecision, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Persona_reddit_action_with_bifrost_identity_and_heimdall_reference_is_authorized_and_stored()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
|
||||
var requestPayload = JsonSerializer.Serialize(new
|
||||
{
|
||||
actorKind = "Persona",
|
||||
actorName = "Epiphany Persona",
|
||||
targetSurface = "Reddit",
|
||||
actionKind = "RedditPost",
|
||||
targetLocator = "r/GameCultOrg",
|
||||
sourceKind = "epiphany_persona_reddit",
|
||||
sourceId = "persona-speech-audit-authorized",
|
||||
authorityReference = "epiphany.persona_speech_audit",
|
||||
bifrostIdentity = "epiphany.Persona",
|
||||
heimdallCapabilityReference = "heimdall:reddit:capability:epiphany-persona",
|
||||
epiphanyRunId = "epiphany-run-identity-gate",
|
||||
epiphanyLaneId = "Persona",
|
||||
epiphanyAgentIdentity = "epiphany.Persona",
|
||||
title = "Persona Reddit thread",
|
||||
summary = "This should pass with Bifrost identity and Heimdall reference."
|
||||
});
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, "/bridge/actions/request");
|
||||
request.Headers.Add("X-Bifrost-Bridge-Token", "test-bridge-token");
|
||||
request.Content = new StringContent(requestPayload, Encoding.UTF8, "application/json");
|
||||
|
||||
using var response = await client.SendAsync(request);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
||||
var action = await response.Content.ReadFromJsonAsync<BridgeActionHttpResult>();
|
||||
Assert.NotNull(action);
|
||||
Assert.Equal("Authorized", action.Status);
|
||||
|
||||
using var scope = _factory.Services.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<BifrostDbContext>();
|
||||
var savedAction = dbContext.BridgeActions.Single(x => x.Id == action.Id);
|
||||
|
||||
Assert.Equal(BridgeActionStatus.Authorized, savedAction.Status);
|
||||
Assert.Equal("epiphany.Persona", savedAction.BifrostIdentity);
|
||||
Assert.Equal("heimdall:reddit:capability:epiphany-persona", savedAction.HeimdallCapabilityReference);
|
||||
Assert.Equal("epiphany-run-identity-gate", savedAction.EpiphanyRunId);
|
||||
Assert.Equal("Persona", savedAction.EpiphanyLaneId);
|
||||
Assert.Equal("epiphany.Persona", savedAction.EpiphanyAgentIdentity);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Local_bridge_token_can_record_dispatch_run_lifecycle()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1026,6 +1026,15 @@ async function beginBridgeAction(options, action) {
|
|||
sourceKind: optionalString(options["source-kind"]) ?? optionalString(process.env.BIFROST_BRIDGE_SOURCE_KIND) ?? "",
|
||||
sourceId: optionalString(options["source-id"]) ?? optionalString(process.env.BIFROST_BRIDGE_SOURCE_ID) ?? "",
|
||||
authorityReference: optionalString(options["authority-ref"]) ?? optionalString(process.env.BIFROST_BRIDGE_AUTHORITY_REF) ?? "",
|
||||
bifrostIdentity: optionalString(options.identity) ?? optionalString(process.env.BIFROST_IDENTITY) ?? "",
|
||||
heimdallCapabilityReference:
|
||||
optionalString(options["heimdall-capability-ref"]) ??
|
||||
optionalString(process.env.HEIMDALL_CAPABILITY_REF) ??
|
||||
optionalString(process.env.BIFROST_HEIMDALL_CAPABILITY_REF) ??
|
||||
"",
|
||||
epiphanyRunId: optionalString(options["epiphany-run-id"]) ?? optionalString(process.env.EPIPHANY_RUN_ID) ?? "",
|
||||
epiphanyLaneId: optionalString(options["epiphany-lane-id"]) ?? optionalString(process.env.EPIPHANY_LANE_ID) ?? "",
|
||||
epiphanyAgentIdentity: optionalString(options["epiphany-agent-identity"]) ?? optionalString(process.env.EPIPHANY_AGENT_IDENTITY) ?? "",
|
||||
workItemId: optionalString(options["work-item-id"]) ?? null,
|
||||
motionId: optionalString(options["motion-id"]) ?? null,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue