Disco ParrotDisco Parrot Home
Docs
Request a Demo

Credential leases

How a credential reaches an agent run in Disco Parrot, for one operation and no longer. The just-in-time lease, scoped to a capability and a destination, granted or denied on the record, delivered host-side at the moment of use, and gone when the operation ends.

The secret policy keeps your keys out of the agent's hands. This page is about the other half of that arrangement: when a run genuinely needs to use a credential, how does it get one without ever holding it? The answer is a lease, a short-lived, narrowly scoped grant the platform mints at the moment of use, and the way it works is the reason an agent can push to your repository or call a connected tool without a single one of your standing keys ever entering its world.

A lease is the runtime half of "the agent never holds the keys." The approved actions concept page is the everyday version of this idea; this is the version for the person who has to vouch for it.

The agent asks, the platform grants

The pattern is the important thing, so it is worth stating before the parts. The agent does not reach into a vault. It asks the platform for permission to use a credential for a specific purpose, and the platform decides. If the answer is yes, what the agent gets back is not the key. It gets an opaque lease identifier, a time the lease expires, and a hint about how the credential will be delivered, an environment variable name, say. The value itself stays on the server.

When the agent then runs the operation the lease was for, the platform resolves the real credential from the vault host-side, at that moment, hands it to the single command that needs it, watches the command finish, and ends the lease. The agent never sees the value at request time, never sees it at use time, and cannot hold, copy, renew, or revoke the lease. It asked for the use of a key; the platform did the rest.

The agent asksa capability + a destination + a reasonThe platform decideschecks the policy; grants or deniesA grant, not a keyan opaque lease id + an expiry + a delivery hintUsed at the momentvalue resolved host-side, handed to one commandGonethe lease ends; the value is cleaned upThe agent asks for the use of a key; the platform does the rest. The value never reaches the agent.
The agent never reaches into the vault. It asks the platform to use a credential for a specific purpose; the platform decides, returns an opaque lease rather than the key, resolves the real value host-side only at the moment of use, hands it to the single command that needs it, and ends the lease. The agent cannot hold, copy, renew, or revoke it.

This is what lets the credential stay behind the boundary while the work still gets done. The agent's part is to say what it needs and why; the platform's part is to check that, fetch the value at the last possible moment, deliver it to the narrowest possible place, and clean up after.

Scoped to one purpose, one destination, one window

A lease is not a general grant of a key, and that is the whole point: it is bound so tightly on every axis that the worst a stolen one could do is almost nothing, and a reviewer can read exactly how far it reaches before deciding to trust it. Five bounds do that work.

  • A capability. The narrow purpose the lease is for, like repo.push or a call to a specific connected tool. A lease minted for one capability is useless for another, and a run can only ask for capabilities its sandbox profile declares, so the set of things an agent could even request a credential for is decided in configuration, not at the agent's discretion.
  • An audience. The destination the credential is scoped to, like api.github.com. The same capability can carry different secrets for different destinations, and the lease names exactly which one.
  • A delivery channel. How the credential will reach the command, drawn from the fixed set the secret policy allows: one command's environment, a temporary file, a git helper.
  • A time window. A short expiry measured in minutes. A grant to push to Git lasts about ten minutes; a token handed to an external tool can be as short as a minute. When the window closes, the lease is dead whether or not it was used.
  • A use count. Most leases are good for a single use and then complete. A few, like the git helper that a multi-step command leans on, allow a small handful. None are open-ended.
A capabilitythe narrow purpose, like repo.pushAn audiencethe destination, like api.github.comA delivery channelone command's env, a temp file, a git helperA time windowminutes: a Git push ~10, a tool token ~1A use countone use for most, a small handful for a fewScoped to one purpose,one place, one short window.
A lease is bound on every axis a reviewer would want it bound on: a capability, a destination, a delivery channel, a short window, and a use count. The most a compromised run could carry off is a credential scoped to one purpose and one place, good for a minute or ten and one use or a few.

Put together, these mean the blast radius of a lease is tiny by construction. The most a compromised run could carry off is a credential scoped to one capability, one destination, one delivery channel, good for a minute or ten and one use or a few. That is the difference between leaking a standing key and leaking a token that has already nearly expired and can only do the one thing it was minted for.

Granted or denied, and always on the record

A lease request is evaluated against the policy, and it can be turned down. The reasons are specific, and each one is a wall a reviewer can name: the capability is not one this sandbox is allowed to request, the requested delivery channel does not match what the capability permits, the person behind the run is missing a required permission, the requested lifetime is longer than the policy allows, the requested use count is higher than the channel allows, or the run has already asked for more leases than its rate allows. That last one is a real, numbered ceiling: a single run is held to a small number of lease requests a minute and a capped number over its whole life, so a run that started misbehaving cannot grind out an unbounded stream of grants. A request that clears all of these is granted; one that fails any is denied with the reason.

Requestedcapability + audienceEvaluatedagainst the policyDeniedwith the reasonGrantedconsumed at useCompleteduses spentExpired window closedEvery step is on the audit trail, recording the grant and the outcome, never the credential value.
A lease is requested, then granted or denied. A granted lease is consumed when the operation runs, and ends as completed when its uses are spent or expired when its window closes. Every step is an event on the audit trail, recording the capability, destination, channel, lifetime, use count, and outcome, and never the credential value.

The point of writing every step down is that after the fact you can reconstruct the full life of any credential grant without ever seeing the credential. A lease is requested, then granted or denied; a granted one is consumed when the operation runs, and ends as completed when its uses are spent or expired when its window closes. Each of those is an event on the audit trail, recording the capability, the destination, the delivery channel, the lifetime, the use count, and the outcome. What is never on the record is the credential value. The trail shows that a lease for repo.push to api.github.com was granted, used once, and completed; it does not show, because it never holds, the token that did the pushing. The same write-only rule that governs the vault governs the lease record.

add_photo_alternate
Screenshot to capture
The audit log view under Settings, dark theme, filtered to credential-lease events. A table of rows, each with an actor (a person's name with a small avatar; one row marked with an agent glyph for the agent's run), an action ('Lease granted', 'Lease consumed', 'Lease completed', and one 'Lease denied' row), a target reading 'repo.push to api.github.com', and a timestamp. The 'Lease granted' row is expanded to show detail lines 'capability: repo.push', 'audience: api.github.com', 'channel: git helper', 'expires: 10m', 'uses: 1'. The 'Lease denied' row shows a detail line 'reason: lifetime exceeds policy'. No credential value appears in any row. Surface #131316, border #27272a.
save as: public/docs-media/audit-credential-leases.png
Caption when added: A credential grant is on the record from request to completion: the capability, the destination, the channel, the lifetime, and the outcome. What is never on the row is the value the lease stood for.

How a lease reaches the run, and leaves it

When a granted lease is consumed, the platform delivers the credential through the channel the lease named and removes it the instant the work is done. To a single command's environment, where one process reads it and exits. To a temporary file with restrictive permissions that is deleted when the command returns. Through a git helper that hands git the token only when it asks. The cleanup is not best-effort; it runs after the command finishes, whether the command succeeded or failed.

A detail worth stating plainly, because it is the one a careful reviewer asks about: a lease delivers its value to a single command's patch, the environment or files of one exec, and never to the sandbox's standing environment. So a lease does not quietly re-introduce a key into the very environment the secret policy forbids it from. The boundary that refuses a standing managed key is never bypassed by a lease, because a lease was never a standing thing.

Nothing about this survives the operation. The credential was resolved at the moment of use, lived for the length of one command, and was gone before the next one ran, never written to the container's standing environment and never baked into its image. This is why a disposed sandbox holds no secret to find: there was never a credential at rest on its disk to begin with, only a series of leases that each came and went.

This is how Maya Rodriguez's flow opens a pull request on the Insights project. When the agent reaches the push, it asks for a repo.push lease to GitHub; the platform checks that her run is allowed it, mints a fresh token from the workspace's repository credential at that moment, hands it to the push command alone, and lets it expire minutes later. Her repository sees a normal push; the audit trail records a lease granted to her run and completed; and at no point did the agent, or the container it ran in, hold a standing copy of the credential the token was minted from.

What a reviewer checks

A security owner reviewing this does not have to take "short-lived and scoped" on trust. They pull the audit trail and filter it to credential-lease events, and the record answers their questions directly. Was anything granted that should not have been? Every grant names its capability and destination, so a lease for repo.push to api.github.com is legible at a glance and an unexpected pair stands out. How long did a credential live? The granted and completed events bracket it, usually minutes apart. Did a denied request signal a misconfiguration or an attempt? The denial carries its reason. None of these checks asks the reviewer to inspect a running agent or trust a value they cannot see, because the value was never in the record to begin with. The grant is the audit; the key is not.

Why leases work this way

The shape of a lease follows from a single goal: make the worst case small. A standing credential in an agent's environment is a worst case the size of the credential, everything it can reach, for as long as it lives. A lease replaces that with a worst case the size of one operation, for the length of one command. The credential is present exactly when the work needs it and absent every other moment, which is the smallest window a real operation can run in.

Binding a lease to a capability, a destination, a channel, a window, and a use count is what makes that window legible rather than merely short. A reviewer does not have to trust that a credential was used carefully; they can read that it was scoped to one purpose and one place, granted for minutes, used once, and recorded. And resolving the value host-side at the moment of use, never storing it in the lease and never returning it to the agent, is what keeps the grant from becoming the very thing it was meant to avoid. The lease is a permission, not a key. The key never leaves the server.

For the person who owns security, the lease is the answer to "what is the blast radius of a compromised run." It is a credential scoped to one capability and one destination, expiring in minutes, used once, and on the record, rather than a standing key with the run of your systems. The grant is auditable by construction; the value is never in it.

For an engineer, the lease is the thing that lets an agent push code or call a tool on your behalf without a key in sight. A fresh, short-lived credential is minted for the one operation, delivered to the one command, and cleaned up after, so you never paste a token into a place an agent could read, and nothing is left behind to rotate in a panic later.

For a platform engineer, the delivery model is the detail to check: a credential resolved at consumption time, written to a single command's patch or a restricted temporary file, removed after the command returns, never to the container's standing environment. The lease record carries the capability, audience, channel, lifetime, and use count, and never the value.

For a prospect evaluating the platform, leases are why agent autonomy and credential safety are not in tension here. The keys are present enough to do the work and absent enough that there is nothing to leak, because every credential that moves moves as a short-lived, scoped, recorded grant rather than a standing secret in the agent's hands.