Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copy this file to .env and fill in values.
# NEVER commit .env — it contains secrets.

### GIT ###
# GitHub personal access token used for git operations inside the container (replaces ~/.ssh host mount)
# Required permission: `repo` (classic PAT) or equivalent fine-grained repository permissions.
GIT_REMOTE_USERNAME=github_username
GIT_REMOTE_PAT=github_pat_REPLACE_ME

# Git identity inside the container (replaces ~/.gitconfig host mount)
GIT_AUTHOR_NAME=Firstname Lastname
GIT_AUTHOR_EMAIL=firstname.lastname@econ.uzh.ch

# opam Package Manager
OPAMSOLVERTIMEOUT=180
OPAMWORKINGDIR=true

### PROJECT SPECIFIC ###
VERSION=dev
61 changes: 0 additions & 61 deletions .devcontainer/Dockerfile

This file was deleted.

41 changes: 0 additions & 41 deletions .devcontainer/README.md

This file was deleted.

34 changes: 34 additions & 0 deletions .devcontainer/devcontainer-lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"features": {
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-common:1": {
"version": "1.3.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-common@sha256:bcdb1ae6f36e87194f5931a0a0b499302f1cfd66975ce273a8bf7a27aae3bd85",
"integrity": "sha256:bcdb1ae6f36e87194f5931a0a0b499302f1cfd66975ce273a8bf7a27aae3bd85"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-git-credentials:1": {
"version": "1.0.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-git-credentials@sha256:1550cbc5cacd684eb8e381bbe633a941097106766ceab4392dfb1e3b4ec2318d",
"integrity": "sha256:1550cbc5cacd684eb8e381bbe633a941097106766ceab4392dfb1e3b4ec2318d"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-hadolint:1": {
"version": "1.1.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-hadolint@sha256:fac537456f661a25cdd4a418b468810ac3395e553f6c3d791387201eab28d113",
"integrity": "sha256:fac537456f661a25cdd4a418b468810ac3395e553f6c3d791387201eab28d113"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-ocaml:1": {
"version": "1.0.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-ocaml@sha256:1b2f40ff0fd48ad43255e34f78e93c041fb85a4673c71736b8e7a06657785d0d",
"integrity": "sha256:1b2f40ff0fd48ad43255e34f78e93c041fb85a4673c71736b8e7a06657785d0d"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-version:2": {
"version": "2.0.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-version@sha256:c3168d4bfa246b0e0780f07571cb1bb9d98d60dde78cc1a8e9868ceb0d9a7ab7",
"integrity": "sha256:c3168d4bfa246b0e0780f07571cb1bb9d98d60dde78cc1a8e9868ceb0d9a7ab7"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-wait-for-databases:1": {
"version": "1.0.0",
"resolved": "cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-wait-for-databases@sha256:3797759d376f94f29c56d6319418b8db1e3913b0e4793febcb2eef6122bdd69e",
"integrity": "sha256:3797759d376f94f29c56d6319418b8db1e3913b0e4793febcb2eef6122bdd69e"
}
}
}
59 changes: 23 additions & 36 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,52 +1,39 @@
// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/python-3 or the
// devcontainer docu https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference
{
"name": "Guardian dev",
"dockerComposeFile": "./docker-compose.yml",
"service": "dev",
"runServices": [
"dev",
"database"
// "adminer" // uncomment if adminer should run to see the database
// "adminer"
],
"workspaceFolder": "/workspace",
"remoteEnv": {
"VERSION": "dev",
"OPAMWORKINGDIR": "true",
"OPAMSOLVERTIMEOUT": "180"
"features": {
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-common:1": {},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-git-credentials:1": {
"git_remote_host": "github.com"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-hadolint:1": {},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-wait-for-databases:1": {
"databases": "dev/test"
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-ocaml:1": {
"opam_version": "2.3",
"folders": [
"/workspace/_build",
"/home/opam/.cache"
]
},
"cr.gitlab.uzh.ch/econ/it/devcontainer-features/econ-version:2": {
"version_source": "guardian.opam::^version: \\\"([^\\\"]+)\\\"",
"ocaml": true
}
},
"postCreateCommand": ".devcontainer/wait-for-database.sh test .devcontainer/postCreate.sh",
// Use 'settings' to set *default* container specific settings.json values on container create.
// You can edit these settings after create using File > Preferences > Settings > Remote.
"postCreateCommand": "wait-for-databases make deps",
"customizations": {
"vscode": {
"settings": {
"terminal.integrated.profiles.linux": {
"zsh": {
"path": "/bin/zsh"
}
},
"terminal.integrated.defaultProfile.linux": "zsh",
"editor.formatOnSave": true,
"files.associations": {
"*.ml": "ocaml",
"*.mli": "ocaml"
},
"git.mergeEditor": false,
"ocaml.sandbox": {
"kind": "global"
}
},
// Add the IDs of extensions you want installed when the container is created in the array below.
"extensions": [
"donjayamanne.githistory",
"eamodio.gitlens",
"exiasr.hadolint",
"irongeek.vscode-env",
"ocamllabs.ocaml-platform",
"DavidAnson.vscode-markdownlint",
"ms-vscode.makefile-tools"
"Anthropic.claude-code"
]
}
}
Expand Down
23 changes: 12 additions & 11 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
services:
dev:
container_name: guardian_dev
build:
context: .
dockerfile: Dockerfile
image: ocaml/opam:debian-12-ocaml-5.3
env_file: [.env]
volumes:
# default user is "opam"
- ..:/workspace:cached
- opam:/home/opam/.opam:cached
- build:/workspace/_build:cached
- ${HOME}/.gitconfig:/home/opam/.gitconfig:ro
depends_on: [ database ]
ports: [ 3020:3000 ]
command: /workspace/.devcontainer/wait-for-database.sh test sleep infinity
- db:/databases/dev/:ro
- ${HOME}/.claude:/home/opam/.claude
depends_on: [database]
ports: [3020:3000]
command: sleep infinity

database:
container_name: guardian_database
image: mariadb:10.6.3
command: --max_allowed_packet=629145600
ports: [ 3320:3306 ]
ports: [3320:3306]
environment:
- TZ=Europe/Zurich
- MYSQL_ALLOW_EMPTY_PASSWORD='yes'
- MYSQL_ROOT_HOST=%
- MYSQL_DATABASE=development
- MYSQL_USER=root
volumes:
- ./data/db:/var/lib/mysql
- db:/var/lib/mysql
- ./init:/docker-entrypoint-initdb.d/:ro

adminer:
image: adminer:standalone
restart: always
ports: [ 8080:8080 ]
depends_on: [ database ]
ports: [8080:8080]
depends_on: [database]

volumes:
opam:
build:
db:
14 changes: 0 additions & 14 deletions .devcontainer/postCreate.sh

This file was deleted.

16 changes: 0 additions & 16 deletions .devcontainer/wait-for-database.sh

This file was deleted.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
_build/
.devcontainer/data
.env*
!.env.example
.DS_Store
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [unreleased](https://github.com/uzh/guardian/tree/HEAD)

### Added

- Cache for target uuid to model resolution, so cached validations no longer require a database round trip
- Indexes on `role` for `guardian_actor_roles` and `guardian_actor_role_targets`

### Changed

- Cache invalidation for a single actor now bumps a per-actor generation (and a global epoch for full clears) instead of scanning the whole cache; keys are snapshotted when a validation starts so an invalidation that races an in-flight validation is not lost
- Role permission changes invalidate the cache in one step instead of querying and clearing all affected actors
- `PermissionOnTarget.remove_duplicates` runs in linearithmic instead of quadratic time
- `ActorRole.find_by_actor` and `find_by_target` use `UNION ALL`; validation queries use inner joins where applicable
- `clean` and `delete` clear the caches

### Removed

- Redundant single-column indexes that duplicated unique-constraint prefixes

### Fixed

- Version prefix of sexp dependency

## [0.4.0](https://github.com/uzh/guardian/tree/0.4.0) - 2026-04-07

### Added
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,23 @@ Example usage:

## Development

A guide how to setup the project with devcontainers can be found in [this README](./.devcontainer/README.md).
This project runs in a DevContainer. All credentials are passed via a local `.env` file — no host SSH keys required.

1. Follow the general DevContainer instructions in the [Engineering Wiki](https://gitlab.uzh.ch/econ/it/engineering/-/wikis/2_best-practices/DevContainer).
1. Copy the env template and fill in the values: `cp .devcontainer/.env.example .devcontainer/.env`
1. Click the `><` icon in the bottom-left corner of VS Code and select **Reopen in Container**.

> **NOTE**: When the setup is fully installed, select `View` -> `Command Palette...` and run the command `OCaml: Restart Language Server`

### Database View

There is an `Adminer` container added to the development package. To be able to use it, follow these few steps:

1. Uncomment its line in the `.devcontainer/devcontainer.json` under `runServices`
1. Use `Remote-Containers: Rebuild Container` that it will also create and startup the `Adminer` container
1. Open your web browser and open `localhost:8080`
1. Use the _development_ credentials defined for the development database in your `.env` file
(default: `user: root`, `password: <empty/none>`, `host: database`, `database: development` )

### Commands

Expand Down
4 changes: 2 additions & 2 deletions backend/caqti_encoders.ml
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ let custom
=
fun ~encode ~decode schema ->
let typ = Schema.make_type schema in
let encode data = encode data |> Result.map Data.make_value in
let encode data = encode data |> CCResult.map Data.make_value in
Caqti_type.custom ~encode ~decode typ
;;

let custom_ok
: type a b.
encode:(b -> a Data.t) -> decode:(a -> b) -> a Schema.t -> b Caqti_type.t
=
let open CCFun in
let open CCFun.Infix in
fun ~encode ~decode schema ->
let typ = Schema.make_type schema in
let encode = CCResult.(encode %> return %> map Data.make_value) in
Expand Down
Loading