Skip to content
Open
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
75e6d6e
feat(typescript): add tutorial for writing policies with typescript/j…
esosaoh Sep 1, 2025
e747c53
Update docs/tutorials/typescript/01-intro-typescript.md
esosaoh Sep 4, 2025
f3b103e
Update docs/tutorials/typescript/02-scaffold.md
esosaoh Sep 4, 2025
90a41db
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
4a4f373
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
a2da140
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
f1460b2
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
8d37595
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
f702460
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
14e756b
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
65b6beb
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
e3be4b3
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 4, 2025
410402a
Update docs/tutorials/typescript/02-scaffold.md
esosaoh Sep 4, 2025
aa9ef5c
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
bb47b23
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
91ab0ff
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
5a2763c
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
895352c
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
bf2f19a
Update docs/tutorials/typescript/05-e2e-tests.md
esosaoh Sep 6, 2025
2337e5b
Update docs/tutorials/typescript/02-scaffold.md
esosaoh Sep 6, 2025
936e53e
Update docs/tutorials/typescript/01-intro-typescript.md
esosaoh Sep 6, 2025
5bc5556
Update docs/tutorials/typescript/01-intro-typescript.md
esosaoh Sep 6, 2025
f943284
Merge branch 'kubewarden:main' into main
esosaoh Sep 6, 2025
cc0902a
docs: address PR reviews
esosaoh Sep 6, 2025
8fe78fa
docs: move tutorial docs to correct section
esosaoh Sep 6, 2025
0add942
docs: remove tutorial from wrong location
esosaoh Sep 8, 2025
bf64702
Apply suggestions from code review
flavio Sep 9, 2025
317fb1d
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
jhkrug Sep 9, 2025
66716e8
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
jhkrug Sep 9, 2025
b2bd1a6
Create _category.json
jhkrug Sep 10, 2025
7cf07ca
Create _category_.json
jhkrug Sep 10, 2025
222a851
Delete docs/tutorials/writing-policies/typescript/_category.json
jhkrug Sep 10, 2025
a0588cc
docs: make changes from pr review
esosaoh Sep 17, 2025
9d71d20
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 18, 2025
f34bdf3
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 18, 2025
42fcbda
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
e506224
Update docs/tutorials/writing-policies/typescript/02-scaffold.md
esosaoh Sep 18, 2025
828663f
Update docs/tutorials/writing-policies/typescript/03-policy-settings.md
esosaoh Sep 18, 2025
b54aabb
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
esosaoh Sep 18, 2025
ce7080e
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
esosaoh Sep 18, 2025
1ce0b99
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
esosaoh Sep 18, 2025
d36046f
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
esosaoh Sep 18, 2025
b10c58b
Update docs/tutorials/writing-policies/typescript/05-e2e-tests.md
esosaoh Sep 18, 2025
6449f20
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
f111b6b
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
4cc82b0
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
3770251
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
4998535
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
b39696c
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
6fc3ede
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
0c183ea
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 18, 2025
ffecbf1
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
1ffb025
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
bb8a6af
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
b142aa1
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
9f8c2b1
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
f58fd1a
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
155314d
Update docs/tutorials/writing-policies/typescript/03-policy-settings.md
esosaoh Sep 22, 2025
fb9a33f
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 22, 2025
d0059f7
Update docs/tutorials/writing-policies/typescript/02-scaffold.md
esosaoh Sep 22, 2025
b80e3a8
Update docs/tutorials/writing-policies/typescript/01-intro-typescript.md
esosaoh Sep 22, 2025
44db024
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 22, 2025
1c7b70d
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 22, 2025
117c4f1
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Sep 22, 2025
38e002d
`.wasm`
esosaoh Sep 22, 2025
5fee132
Update docs/tutorials/writing-policies/typescript/04-validation.md
esosaoh Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions docs/tutorials/writing-policies/typescript.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
sidebar_label: Writing policies in TypeScript/JavaScript
sidebar_position: 010
title: Writing policies in TypeScript/JavaScript
description: A tutorial introduction to writing policies in TypeScript/JavaScript.
keywords: [kubewarden, kubernetes, writing policies in TypeScript, writing policies in JavaScript]
doc-type: [tutorial]
doc-topic: [kubewarden, writing-policies, typescript, javascript, introduction]
doc-persona: [kubewarden-policy-developer]
---

<head>
<link rel="canonical" href="https://docs.kubewarden.io/tutorials/writing-policies/intro-typescript"/>
</head>

:::note
TypeScript/JavaScript support for WebAssembly is rapidly evolving.
This page was last revised in September 2025.
:::

As stated on the [official website](https://www.typescriptlang.org/):

> TypeScript extends JavaScript by adding types.
>
> By understanding JavaScript, TypeScript saves you time catching errors and
> providing fixes before you run code.

Kubewarden uses [Javy](https://github.com/bytecodealliance/javy) (a Bytecode Alliance project) to build WebAssembly binaries from JavaScript and TypeScript.

> Javy takes your JavaScript code and executes it in a WebAssembly context.
>
> It features an embedded QuickJS engine compiled to WebAssembly that can execute JavaScript.
>
> The project provides both a CLI and a set of APIs for embedding and customizing the behavior when running JavaScript in WebAssembly.

The Kubewarden project currently uses Javy for these reasons:

- Mature JavaScript engine (QuickJS) compiled to WebAssembly
- Support for [WASI interface](../wasi/01-intro-wasi.md) through custom host functions
- Smaller binary sizes compared to other JavaScript-to-WebAssembly solutions
- Active development and maintenance by the Bytecode Alliance

## Javy limitations

Javy runs JavaScript in a sandboxed WebAssembly environment with certain constraints:

- **WASI environment only**: Access limited to stdin/stdout/stderr and explicitly provided host capabilities
- **No Node.js APIs**: Standard Node.js modules like `fs`, `http`, or `crypto` aren't available
- **Limited standard library**: Only core JavaScript features and explicitly enabled APIs are accessible
- **Single-threaded execution**: No support for Web Workers or multi-threading
- **STDOUT restrictions**: Writing to STDOUT will break your policy - use STDERR for logging instead

Despite these limitations, Javy provides sufficient capabilities for writing effective Kubewarden validation policies through the host capabilities system.

## Tooling

Writing Kubewarden policies requires:

- **Node.js**: Version 18 or higher
- **npm**: For dependency management
- **TypeScript**: Recommended for type safety (optional)

:::warning
Ensure you're using Node.js 18 or higher. Older versions may not be compatible with the compilation toolchain.
:::

These TypeScript/JavaScript libraries are useful when writing a Kubewarden policy:

- [Kubewarden JavaScript SDK](https://github.com/kubewarden/policy-sdk-js): Provides structures and functions reducing the amount of code necessary. It also provides test helpers and access to all host capabilities.
- [Kubernetes TypeScript types](https://github.com/silverlyra/kubernetes-types): Provides TypeScript definitions for all Kubernetes resources, enabling type-safe policy development.

The Kubewarden project provides a [template JavaScript/TypeScript policy project](https://github.com/kubewarden/js-policy-template) you can use to create Kubewarden policies.

## Getting the toolchain

The easiest way to get the complete toolchain is by using the Kubewarden JavaScript SDK, which includes the Javy compilation plugin:

```bash
npm install kubewarden-policy-sdk
```

The Javy plugin binary is automatically included and you can find it at:

```
node_modules/kubewarden-policy-sdk/plugin/javy-plugin-kubewarden
```

## Tutorial prerequisites

During this tutorial you need these tools on your development machine:

- **Node.js**: Version 18 or higher with npm for dependency management
- [**`bats`**](https://github.com/bats-core/bats-core): Used to write the tests and automate their execution
- [**`kwctl`**](https://github.com/kubewarden/kwctl/releases): CLI tool provided by Kubewarden to run its policies outside of Kubernetes, among other actions. It's covered in [the testing policies section](../../testing-policies/index.md) of the documentation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reminder: here we will have to tell the user they have to use kwctl 1.30 or later

123 changes: 123 additions & 0 deletions docs/tutorials/writing-policies/typescript/02-scaffold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
sidebar_label: New validation policy
sidebar_position: 020
title: Creating a new validation policy
description: Creating a new validation policy for Kubewarden using TypeScript.
keywords: [kubewarden, kubernetes, writing policies in TypeScript, new validation policy]
doc-type: [tutorial]
doc-topic: [kubewarden, writing-policies, typescript, creating a new validation policy]
doc-persona: [kubewarden-policy-developer]
---

<head>
<link rel="canonical" href="https://docs.kubewarden.io/tutorials/writing-policies/typescript/scaffold"/>
</head>

This tutorial covers creating a policy that validates the hostnames of Pod objects.

The policy is to reject all Pods that use one or more hostnames on the deny list.
You provide policy configuration using runtime settings.

To summarize, the policy settings should look like this:

```yaml
denied_hostnames:
- bad-host
- forbidden-host
```

The policy rejects the creation of this Pod:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostname: bad-host
containers:
- name: nginx
image: nginx:latest
```

But, it accepts the creation of this Pod:

```yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
hostname: allowed-host
containers:
- name: nginx
image: nginx:latest
```

## Scaffolding a new policy project

You can create a new policy project using the [template repository](https://github.com/kubewarden/js-policy-template). Select the "Use this template" green button near the top of the page and follow GitHub's wizard.

Clone the repository locally and update the `package.json` file to reflect your policy details:

```json
{
"name": "your-policy-name",
"version": "1.0.0",
"description": "Your policy description",
"repository": {
"type": "git",
"url": "https://github.com/your-username/your-policy-name"
}
}
```

Make sure to use a repository path that matches your actual GitHub repository.

## Testing

Provided the necessary tools are in place, the `make all` command builds the `annotated-policy.wasm` target. The command `make e2e` runs tests using `bats` with `kwctl`.

Copy link
Contributor

@jhkrug jhkrug Sep 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When trying make all I am unsuccessful. Any suggestions?

Using

[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
‽ node --version
v24.0.1
[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
‽ javy --version
javy 6.0.0
[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
‽ kwctl --version
kwctl 1.28.1

Use the `info` command to display system information.

[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
‽ bats --version
Bats 1.12.0
[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
‽

I get:

⸘ git remote -v
origin	[email protected]:jhkrug/test-js-policy.git (fetch)
origin	[email protected]:jhkrug/test-js-policy.git (push)
[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]
⸘ make clean
npm cache clean --force
npm warn using --force Recommended protections disabled.
rm -f policy.wasm annotated-policy.wasm
rm -rf dist dist-ts node_modules package-lock.json
[~/projects/suse/kubewarden/testing/test-js-policy][main *|u=]
‽ make all
npm install
npm warn deprecated [email protected]: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
npm warn deprecated [email protected]: Glob versions prior to v9 are no longer supported

added 399 packages, and audited 400 packages in 14s

59 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
npm run build

> [email protected] build
> npx webpack --config webpack.config.cjs

asset bundled.js 5.52 KiB [emitted] [minimized] (name: main)
asset types.d.ts 430 bytes [emitted]
asset index.d.ts 11 bytes [emitted]
./src/index.ts 3.84 KiB [built] [code generated]
./node_modules/kubewarden-policy-sdk/dist/bundle.js 3.85 KiB [built] [code generated]
webpack 5.101.3 compiled successfully in 1530 ms
npm install

added 1 package, and audited 401 packages in 996ms

59 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
javy build dist/bundled.js -C plugin=node_modules/kubewarden-policy-sdk/plugin/javy-plugin-kubewarden.wasm -o policy.wasm
Error: Could not process plugin: Using unsupported legacy plugin API
make: *** [Makefile:16: policy.wasm] Error 1
[~/projects/suse/kubewarden/testing/test-js-policy][main|u=]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@esosaoh can you please check and list the needed changes for this to work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Javy team has provided documentation with a steps to migrate to v2.0.0 of the javy-plugin-api: https://crates.io/crates/javy-plugin-api

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything is going to be sorted out once:

Copy link
Contributor Author

@esosaoh esosaoh Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@flavio we need to tag a new version of the sdk when kwctl 1.30 is released

<details>
<summary>Output from the `make` commands</summary>

```console
make all
npx webpack --config webpack.config.cjs
asset bundled.js 5.52 KiB [compared for emit] [minimized] (name: main)
asset types.d.ts 430 bytes [compared for emit]
asset index.d.ts 11 bytes [compared for emit]
./src/index.ts 3.84 KiB [built] [code generated]
./node_modules/kubewarden-policy-sdk/dist/bundle.js 3.85 KiB [built] [code generated]
webpack 5.101.3 compiled successfully in 2280 ms
npm install

up to date, audited 400 packages in 2s

58 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities
```

```console
make e2e
npx webpack --config webpack.config.cjs
asset bundled.js 5.52 KiB [compared for emit] [minimized] (name: main)
asset types.d.ts 430 bytes [compared for emit]
asset index.d.ts 11 bytes [compared for emit]
./src/index.ts 3.84 KiB [built] [code generated]
./node_modules/kubewarden-policy-sdk/dist/bundle.js 3.85 KiB [built] [code generated]
webpack 5.101.3 compiled successfully in 1909 ms
bats e2e.bats
e2e.bats
✓ reject because hostname is on the deny list
✓ accept because hostname is not on the deny list
✓ accept because the deny list is empty
✓ accept because pod has no hostname set
✓ accept non-pod resources

5 tests, 0 failures
```

</details>
109 changes: 109 additions & 0 deletions docs/tutorials/writing-policies/typescript/03-policy-settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
sidebar_label: Defining policy settings
sidebar_position: 030
title: Defining policy settings
description: Defining policy settings for a Kubewarden policy written in TypeScript.
keywords: [kubewarden, kubernetes, defining policy settings, TypeScript]
doc-type: [tutorial]
doc-topic: [kubewarden, writing-policies, typescript, defining-policy-settings]
doc-persona: [kubewarden-policy-developer]
---

<head>
<link rel="canonical" href="https://docs.kubewarden.io/tutorials/writing-policies/typescript/policy-settings"/>
</head>

:::danger Critical: Don't write logging information to STDOUT

Writing to STDOUT breaks your policy. Instead, use STDERR for logging or the logging facility provided by the Kubewarden SDK. The policy's output to STDOUT must only contain the validation response.

:::

First, define the structure that holds the policy settings in `src/types.ts`.

```ts
import type { PodSpec } from 'kubernetes-types/core/v1';
import type { ObjectMeta } from 'kubernetes-types/meta/v1';

/**
* Interface representing policy settings structure.
*/
export interface PolicySettings {
// List of hostnames that are denied by the policy.
denied_hostnames?: string[];
}

/**
* Generic Kubernetes resource interface
*/
export interface KubernetesResource {
apiVersion: string;
kind: string;
metadata: ObjectMeta;
spec?: PodSpec | any;
}
```

## Building Settings instances

Kubewarden policies use two functions that handle settings:

- `validate`: Called during object validation.
- `validateSettings`: Called at policy load time.

In `src/index.ts`, the `validate` function looks like:

```ts
function validate(): void {
try {
const validationRequest = Validation.Validation.readValidationRequest();
const settings: PolicySettings = validationRequest.settings || {};

// Policy logic...
} catch (err) {
console.error('Validation error:', err);
writeOutput(Validation.Validation.rejectRequest(`Validation failed: ${err}`));
}
}
```

## Implementing Settings validation

```ts
function validateSettings(): void {
try {
const settingsInput = Validation.Validation.readValidationRequest();
const settings: PolicySettings = settingsInput as PolicySettings;

if (settings.denied_hostnames && !Array.isArray(settings.denied_hostnames)) {
const errorResponse = new Validation.Validation.SettingsValidationResponse(
false,
'denied_hostnames must be an array of strings',
);
writeOutput(errorResponse);
return;
}

for (const hostname of settings.denied_hostnames || []) {
if (typeof hostname !== 'string') {
const errorResponse = new Validation.Validation.SettingsValidationResponse(
false,
'All hostnames in denied_hostnames must be strings',
);
writeOutput(errorResponse);
return;
}
}

const response = new Validation.Validation.SettingsValidationResponse(true);
writeOutput(response);
} catch (err) {
console.error('Settings validation error:', err);
const errorResponse = new Validation.Validation.SettingsValidationResponse(
false,
`Settings validation failed: ${err}`,
);
writeOutput(errorResponse);
}
}
```
Loading