Skip to main content

ballerina

Use this whenever you are working with ballerina code or editing .bal files — project layout, the bal library lookup flow, verifying the gateway's signed assertion on a contract-backed service, and the bal build && bal test verify step.

Informações da origem

Repositório
wso2/labs-agentic-engineer
Última atividade na origem
5 de outubro de 2026 às 05:01
Idioma detectado do SKILL.md
inglês
Estrelas
25
Forks
24

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
7 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
ballerina
description
Use this whenever you are working with ballerina code or editing .bal files — project layout, the bal library lookup flow, verifying the gateway's signed assertion on a contract-backed service, and the bal build && bal test verify step.
metadata
{"aep":{"kind":"org","audience":["coding"]}}
# Ballerina **Load [code-rules.md](references/code-rules.md) before writing any `.bal` code.** This contains best practices, syntaxes and common patterns for Ballerina code. ## Development workflow ### Creating a New Project When the user asks to create a new project, service, or program from scratch: ```bash bal new <project-name> # scaffolds main.bal + Ballerina.toml cd <project-name> ``` - Read [project-structure.md](references/project-structure.md) for how a Ballerina project is laid out. Write tests only when the user asks — then load [tests.md](references/tests.md). ### Working with OpenAPI Specifications **Load [openapi.md](references/openapi.md) before writing a service or a client that has an OpenAPI document** — one this component implements, or one it calls. It carries the `bal openapi` invocation for each, and where the generated module has to land. ### bal library **Run `bal library --help` before your first lookup, and follow the flow it describes.** It reads a package off Central so you write signatures that exist rather than remembered ones. `--help` is the grammar — the verbs, their flags, the session to walk; each document prints the rules about its own contents. What follows is what you carry into every lookup. #### Working with library ##### Preferences - `ballerina/*` is the standard library; every vendor or third-party connector is `ballerinax/*`. - Prefer a `ballerinax/*` connector over a `trigger.*` package covering the same events. - Balerina has libraries created for working with standards, search before creating your own implementation. - A trailing `// Special Agent Note:` mentions important informations, follow them. eg: Other package references. - **Line one states the document's own length** If it says `· 535 lines` and you filtered using head | tail for 150 which mean the other 385 are gone and the answer can be among them: re-run that call unfiltered before writing anything from it. The library cli is designed to be self contained. You can't judge without the whole output. - -r flag only covers dependant types in the own package. For the external package references, you might need to invoke `bal library type` if you need them. - Tool may return ## Next section: Those are suggestions for your next look up navigation tool. Use them as hints. - Tool might return errors, Handle accoringly based on the error message. ### bal build - An `import` plus `bal build` resolves a package — no manual `Dependencies.toml` edit. - `target/` is the incremental cache — leave it in place. A build that printed `Generating executable` is green; do not re-run `bal build` to confirm it. - Configurables are read at runtime, so env variables or Config.toml is not needed to build. - **`bal build` does NOT run tests.** Any package with a `tests/` directory verifies with `bal build && bal test` — a green build says nothing about a test that guards a correctness invariant. ## Who the caller is: the gateway's signed assertion A service whose `design.json` sets `exposesAPI.auth` implements `specs/design/components/<name>/openapi.yaml`. **The gateway has already done the authorization.** It validated the caller's token and checked the scope each operation declares in that same contract; a request that failed either never reached this process. So this service holds **no operation → scope table**. That `bal openapi` drops the contract's `security` block no longer matters: there is nothing to transcribe, and nothing to keep in sync. What the gateway cannot do is prove to your code that a request *came through it* — any pod that can open a socket to this service can send whatever headers it likes. So it signs a JWT of the caller it authenticated and puts it on the upstream request, and this service verifies that signature against one certificate the platform publishes per environment. From the App Path: ```bash cp "$AEP_SKILLS_DIR/ballerina/assets/gateway_assertion.bal" gateway_assertion.bal ``` If `$AEP_SKILLS_DIR` is unset, copy from `assets/` next to this skill's `SKILL.md` (the BFF mirrors that directory to `.claude/skills/ballerina/`). The file is **verbatim — there is no line to edit**. Two edits, and nothing else: 1. **The generated service becomes interceptable**: ```ballerina service http:InterceptableService / on ep0 { public function createInterceptors() returns AssertionInterceptor => new; // …generated resources, unchanged… } ``` 2. **A resource that needs an identity takes `http:RequestContext ctx`** and calls `requireGatewayCaller(ctx)`, returning its `http:Unauthorized` as-is. Match on the side the model stores — `userId` for a directory id, `requireCallerUsername(caller)` for a login name: ```ballerina // GET /me/claims — the caller's rows, resolved through the assertion and // nothing the client sent. `ownerId` here stores a directory id. resource function get me/claims(http:RequestContext ctx) returns Claim[]|http:Unauthorized { GatewayCaller|http:Unauthorized caller = requireGatewayCaller(ctx); if caller is http:Unauthorized { return caller; } return store.byOwner(caller.userId); } // Same shape when the model stores a login name instead — the only change // is which side of the comparison the assertion supplies. // string|http:InternalServerError name = requireCallerUsername(caller); // if name is http:InternalServerError { return name; } // return store.byManager(name); // GET /claims — every row; a different operation, guarded by claims:read-all resource function get claims() returns Claim[] { return store.all(); } ``` Nothing goes in `Ballerina.toml` or `Dependencies.toml`: `ballerina/crypto`, `ballerina/jwt` and `ballerina/os` are distribution modules that `bal build` resolves from the imports. **Read identity from the verified caller, never from a header.** | Rule | Why | |---|---| | **`requireGatewayCaller(ctx)`** in any resource that needs an identity. | The assertion is the only statement about the caller that a forged request cannot make. | | **Match the caller on the side the model stores** — `userId` for a directory id, `requireCallerUsername(caller)` for a login name. | A UUID compared to a name matches nothing and answers `200 []` — "you own nothing", not "who are you". An identity failure is never an empty list. | | **Never bind `X-User-Id`, `X-User-Scopes`, `X-User-Groups` or `Authorization`** as resource header parameters. | The first three are unsigned — the gateway sets them, and so can anyone else who reaches this pod directly. `Authorization` is stripped. | | **A `security: []` resource reads NO identity at all** and takes no `ctx`. | The gateway serves a public operation with no assertion, so there is no caller to read there. | | **Compare a scope with the asset's `hasScope`.** | It compares whole handles. `string:includes` is the trap — it matches `claims:read` inside `claims:read-all`. | | **Never `http:ServiceConfig { auth: … }`.** | That is listener-side token validation against the identity provider — the coupling the assertion exists to remove. | `hasScope` is never an operation's only check. Whether the operation may be called at all was settled at the gateway, from the contract. A **single-row** read is the same rule at the other end: when the caller holds only the `own` handle and the row belongs to someone else, return **404, not 403** — a caller who may not see a row may not learn it exists from a status code either (`api-management` owns the rule; this is its Ballerina shape). **Verify** a package with `gateway_assertion.bal` in it: ```bash bal build && bal test ``` Write the tests against a **throwaway RSA keypair**: mint an assertion with the private half and export **all three** of `GATEWAY_ASSERTION_CERTIFICATE` (from its self-signed certificate), `GATEWAY_ASSERTION_ISSUER` and `GATEWAY_ASSERTION_HEADER`, so nothing in the test talks to a gateway. Export them **before** `bal test`: without the full trio the interceptor takes its unverified fallback, so every assertion test fails for a reason the output does not name. Cover four cases — a valid assertion is accepted; one signed by a *different* key is a 401; one whose payload was edited after signing is a 401 (never an anonymous caller); and a `security: []` resource answers 200 with no assertion at all. ## Dockerfile When the user asks for a container image — load [dockerfile.md](references/dockerfile.md).
Ver no GitHub