read_prev_login_success
previous with a response predicate and an output-field filter.
Permit a Read only if the immediately preceding event (within 1h) was the
same user’s successful Login — i.e. a Login::response whose
output.result is true. Because previous looks only at timepoint i - 1,
at timepoint 0 there is no predecessor, so the rule can never fire there.
The trace shows all three behaviors:
@0— aReadat timepoint 0: no predecessor exists, so deny (the no-verdict-at-tp0 behavior).@7— aReadwhose immediately preceding event (@5) is alice’s successfulLogin::response(output.result: true) → allow.@31— aReadwhose predecessor (@30) is bob’sLogin::responsewithoutput.result: false; the output-field filter rejects the failed login → deny.
Referenced by guide/04-temporal-expressions.md.
Policy
// `previous` with a response predicate and an output-field filter. Permit a
// Read only if the immediately preceding event (within 1h) was the same
// user's SUCCESSFUL Login (output.result: true). At timepoint 0 there is no
// predecessor, so the rule never fires there.
@id("read_after_prev_login_success")
permit (
principal,
action == Drupe::Action::"Read",
resource
)
when temporal {
previous within 1h Drupe::Action::"Login"::response{ input.user: context.input.user, output.result: true }
};
Schema
namespace Drupe {
type ContentFilterFinding = {
severityScore: decimal
};
type LoginInput = {
server: String,
user: String
};
type LoginOutput = {
result: Bool
};
type PromptAttackFinding = {
severityScore: decimal
};
type ReadInput = {
document: String,
user: String
};
type ReadOutput = { };
type SensitiveInfoFinding = {
confidenceScore: decimal
};
type SystemContext = {
now: datetime
};
entity Gateway;
entity IamEntity = {
id: String
};
entity OAuthUser = {
id: String
} tags String;
entity UnauthenticatedUser;
action "CallTool" in [Action::"Mcp"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
action "Http" appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
action "InvokeAgent" in [Action::"Http"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
input?: { },
system: SystemContext
}
};
action "InvokeLLM" in [Action::"Http"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
input?: { },
system: SystemContext
}
};
action "Login" in [Action::"CallTool"] appliesTo {
principal: [IamEntity, OAuthUser, UnauthenticatedUser],
resource: [Gateway],
context: {
input: LoginInput,
output?: LoginOutput,
system: SystemContext
}
};
action "Mcp" appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
action "Read" in [Action::"CallTool"] appliesTo {
principal: [IamEntity, OAuthUser, UnauthenticatedUser],
resource: [Gateway],
context: {
input: ReadInput,
output?: ReadOutput,
system: SystemContext
}
};
action "UnknownTool" in [Action::"CallTool"] appliesTo {
principal: [OAuthUser, IamEntity, UnauthenticatedUser],
resource: [Gateway],
context: {
system: SystemContext
}
};
}
Trace
@0 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "doc0", user: "alice" }) Drupe::Action::"Read"::request(input: { document: "doc0", user: "alice" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "r0")
@5 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") Drupe::Action::"Login"::response(input: { server: "s1", user: "alice" }, output: { result: true }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "l1")
@7 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "doc1", user: "alice" }) Drupe::Action::"Read"::request(input: { document: "doc1", user: "alice" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "r1")
@30 scope(principal: Drupe::OAuthUser::"bob", resource: Drupe::Gateway::"gw1") Drupe::Action::"Login"::response(input: { server: "s1", user: "bob" }, output: { result: false }, callerPrincipal: Drupe::OAuthUser::"bob", callerResource: Drupe::Gateway::"gw1", requestId: "l2")
@31 scope(principal: Drupe::OAuthUser::"bob", resource: Drupe::Gateway::"gw1") request_context(input: { document: "doc2", user: "bob" }) Drupe::Action::"Read"::request(input: { document: "doc2", user: "bob" }, callerPrincipal: Drupe::OAuthUser::"bob", callerResource: Drupe::Gateway::"gw1", requestId: "r2")
Expected Output
@0 (time point 0): DENY
@7 (time point 1): ALLOW [rules: 0]
@31 (time point 2): DENY