@sapbruno/cf-btp
v0.1.1
Published
SAP Cloud Foundry / BTP credential provider for sapbruno. Extracts xsuaa OAuth2 client_credentials from bound apps via cf CLI.
Maintainers
Readme
@sapbruno/cf-btp
SAP Cloud Foundry / BTP credential provider for sapbruno.
Extracts OAuth2 client_credentials from the xsuaa (or identity) service binding of a deployed
Cloud Foundry app, via the cf CLI. Eliminates the need to hand-copy clientid/clientsecret from
service keys into Bruno env files.
How it works
For each call to fetch(prefix, ctx), the provider:
- Resolves
{ group, branch, app }from the configuredservices[prefix]binding. - Looks up the corresponding CF org from a branch → subaccount map file
(
cf-branch-map.json— see format below). - Ensures a live
cfsession — ifcf targetshows no API endpoint or user, it runscf api <endpoint>andcf auth $SAP_EMAIL $SAP_PASSWORD(or values from provider config). - Runs
cf target -o <org> -s <space>,cf app <app> --guid,cf curl /v3/apps/<guid>/env. - Parses
VCAP_SERVICES.xsuaa[0].credentials— returns{ tokenUrl: <url> + /oauth/token, clientId, clientSecret }.
If no xsuaa binding exists it falls back to the identity service and uses /oauth2/token.
Install
pnpm add -D @sapbruno/cf-btp sapbrunoRequires the cf CLI on your PATH.
Configure
In your sapbruno.config.json:
{
"collections": "./collections",
"environments": {
"dev": {
"auth": { "type": "oauth2-client-credentials" },
"credentialProvider": {
"type": "cf-btp",
"mapFile": "./cf-branch-map.json",
"space": "app",
"cacheTtlSeconds": 300,
"services": {
"my_group_demo": {
"group": "my-group",
"branch": "main",
"app": "my-demo-app"
}
}
}
}
}
}Then register the provider in your sapbruno setup (see sapbruno docs for the provider loader).
cf-branch-map.json format:
{
"my-group": [
{ "branch": "main", "cf_org": "my-cf-org", "environment": "dev", "region": "eu20" },
{ "branch": "dev", "cf_org": "my-cf-org-dev", "environment": "dev", "region": "eu20" }
]
}Environment variables
SAP_EMAIL,SAP_PASSWORD— used for non-interactivecf authwhen no live session is found. Skip these if you prefer to runcf loginyourself before invoking sapbruno.
Per-service options
Each entry under services[prefix] accepts:
group(required) — matches a top-level key inmapFile.branch(required) — matches an entry under that group → determines target CF org.app(required) — the CF app name bound to the xsuaa/identity service.cfSpace— override the defaultspacefor this one service.serviceInstanceName— pick a specific service instance by name when the app has multiple bindings of the same type.preferredService—"xsuaa"(default) or"identity".
Programmatic usage
import { cfBtpProvider } from "@sapbruno/cf-btp";
const provider = cfBtpProvider({
mapFile: "./cf-branch-map.json",
space: "app",
services: {
my_group_demo: { group: "my-group", branch: "main", app: "my-demo-app" },
},
});
const creds = await provider.fetch("my_group_demo", { rootDir: process.cwd(), envName: "dev" });
// { tokenUrl, clientId, clientSecret }Security
- Credentials are only held in memory for the lifetime of the Node process.
cacheTtlSecondscontrols how long a given prefix's creds are reused before re-fetching.- The provider never writes credentials to disk —
sapbrunodoes that into its Bruno env file (same behavior as the upstream provider interface).
License
MIT © dongtran
