diff --git a/.devcontainer/devcontainer-docker-compose.yml b/.devcontainer/devcontainer-docker-compose.yml new file mode 100644 index 0000000..1fc6432 --- /dev/null +++ b/.devcontainer/devcontainer-docker-compose.yml @@ -0,0 +1,42 @@ +services: + # Update this to the name of the service you want to work with in your docker-compose.yml file + devcontainer: + container_name: devcontainer + image: mcr.microsoft.com/devcontainers/base:ubuntu + user: ${RUN_AS:-0:0} + volumes: + # Update this to wherever you want VS Code to mount the folder of your project + - ..:/workspaces:cached + + # Overrides default command so things don't shut down after the process ends. + command: /bin/bash -c "echo \"Visit http://${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-localhost}:8003 and log in as admin/admin to continue\" && sleep infinity" + depends_on: + # Waiting for the frontend ensures the web UX is ready before we display our message + spiffworkflow-frontend: + condition: service_started + + spiffworkflow-frontend: + environment: + - SPIFFWORKFLOW_FRONTEND_RUNTIME_CONFIG_APP_ROUTING_STRATEGY=path_based + + spiffworkflow-backend: + environment: + - SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND=http://${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-localhost}:8003 + - SPIFFWORKFLOW_BACKEND_URL=http://${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-localhost}:8003/api + - SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL=http://${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-localhost}:8003/api/openid + - SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL=http://${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:-localhost}:8004 + - SPIFFWORKFLOW_BACKEND_WSGI_PATH_PREFIX=/api + healthcheck: + test: "curl localhost:${SPIFF_BACKEND_PORT:-8000}/api/v1.0/status --fail" + + spiffworkflow-proxy: + container_name: proxy + image: nginx:latest + ports: + - "8003:8003" + volumes: + - .devcontainer/nginx.conf:/etc/nginx/conf.d/default.conf + depends_on: + - spiffworkflow-frontend + - spiffworkflow-backend + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..470c5da --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,68 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose +{ + "name": "container-based BPMN editor", + + // Update the 'dockerComposeFile' list if you have more compose files or use different names. + // The .devcontainer/docker-compose.yml file contains any overrides you need/want to make. + "dockerComposeFile": [ + "../docker-compose.yml", + "devcontainer-docker-compose.yml" // amendments necessary for the devContainer to work + ], + + // The 'service' property is the name of the service for the container that VS Code should + // use. Update this value and .devcontainer/docker-compose.yml to the real service name. + "service": "devcontainer", + + // The optional 'workspaceFolder' property is the path VS Code should open by default when + // connected. This is typically a file mount in .devcontainer/docker-compose.yml + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + "features": { + // These are commented out because they are incompatible with Zscaler + // We need something like this for the Docker Compose case: + // https://github.com/microsoft/vscode-remote-release/issues/6092#issuecomment-1646739392 + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + + // "ghcr.io/devcontainers/features/github-cli:1": {}, + // "ghcr.io/waqqas/feature/bpmnlint:1": {}, + // "ghcr.io/waqqas/feature/dmnlint:1": {} + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [8000, 8001, 8003, 8004], + + "customizations": { + "codespaces": { + "openFiles": [ + ] + } + }, + "portsAttributes": { + "8000": { + "label": "SpiffWorkflow Backend", + "onAutoForward": "silent" + }, + "8001": { + "label": "SpiffWorkflow Editor", + "onAutoForward": "openBrowser" + }, + "8004": { + "label": "SpiffWorkflow Connector", + "onAutoForward": "silent" + } + } + // Uncomment the next line if you want start specific services in your Docker Compose config. + // "runServices": [], + + // Uncomment the next line if you want to keep your containers running after VS Code shuts down. + // "shutdownAction": "none", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "devcontainer" +} diff --git a/.devcontainer/nginx.conf b/.devcontainer/nginx.conf new file mode 100644 index 0000000..e35262d --- /dev/null +++ b/.devcontainer/nginx.conf @@ -0,0 +1,13 @@ +error_log /dev/stdout info; +server { + listen 8003; + access_log /dev/stdout; + + location / { + proxy_pass http://spiffworkflow-frontend:8001; + } + + location /api { + proxy_pass http://spiffworkflow-backend:8000; + } +} diff --git a/.env b/.env new file mode 100644 index 0000000..0c8f215 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +# Use this directory for process models +SPIFFWORKFLOW_BACKEND_LOCAL_BPMN_SPEC_DIR=. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fb0413a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# See https://code.visualstudio.com/docs/remote/troubleshooting#_resolving-git-line-ending-issues-in-wsl-resulting-in-many-modified-files +* text=auto eol=lf +*.{cmd,[cC][mM][dD]} text eol=crlf +*.{bat,[bB][aA][tT]} text eol=crlf diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf31b93 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# ceq-process-models + +workflows-as-config for NEPA permitting, courtesy of the CEQ + +## What is this? + +The repository captures process models that re-express the [National Renewable Energy Lab (NREL) RAPID Toolkit](https://openei.org/wiki/RAPID) workflows in ready-to-integrate, standards-based formats: [BPMN](https://en.wikipedia.org/wiki/Business_Process_Model_and_Notation), [DMN](https://en.wikipedia.org/wiki/Decision_Model_and_Notation), [JSON Schema](https://json-schema.org/), [RJSF uiSchema](https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/uiSchema) and open source scripting languages. + +## Why is this? + +Federal, state, tribal, and local permitting under the [National Environmental Policy Act (NEPA)](https://ceq.doe.gov/) can be incredibly complex for anyone to understand. The NREL RAPID Toolkit documents workflows for navigating the many regulations and factors that must to be considered when permitting a renewable energy project. + +The [White House Council on Environmental Quality (CEQ)](https://www.whitehouse.gov/ceq/) provides this repository to make implementating NEPA-related permitting workflows across various agencies case-management systems easier and more maintainable. + +You can use these process files to configure a standards-based workflow automation tool, which will supplement (or even provide!) a case-management system for handling permitting applications. + +## Status + +The repository is in a _**pre-alpha**_ state while we lay out pathways for contributors to work productively, even from locked-down local workstations. + +## Contributing + +The process files are version-controlled and we welcome contributions. You will need a [GitHub](https://github.com/) account, if you don't already have one. The easiest way to visualize and edit the process files is to bring them up in a workflow management tool suited to that purpose, and test them as you edit them. We provide instructions below for using [SpiffWorkflow](https://www.spiffworkflow.org/), a capable, free, open-source workflow management system. + +Your organization may have local customizations to these processes which aren't suitable for other implementers. Your organization may also make use of another workflow solution such as [Kogito](https://kogito.kie.org/), [jBPM](https://www.jbpm.org/), [ProcessMaker](https://www.processmaker.com/), or [Camunda](https://camunda.com/). If so, please fork this repository and maintain a downstream, amended version that captures complexity specific to your organization's processes and tech stack. + +Please always consider whether you can make pull-requests to amend process models for the benefit of others, or to add instructions for using your preferred workflow automation tool. + +## Editing the process models in the cloud + +This method is suitable for people who are less technical and who may be working in a locked-down local environment. + +### Pre-requisites + +- Any modern web-browser (eg Chrome, Firefox, Edge) +- Access to [GitHub Codespaces](https://github.com/features/codespaces) for your GitHub account + +### Directions + +_under construction_ + +## Editing the process models locally + +This method is suitable for people comfortable with using git and GitHub, and running containers locally on their machine. + +### Pre-requisites +- [Install a container manager for your local OS to provide the `docker` CLI.](https://docs.google.com/spreadsheets/d/1ZT8m4gpvh6xhHYIi4Ui19uHcMpymwFXpTAvd3EcgSm4/edit?gid=0#gid=0) + - The directions below have been tested with Docker Desktop, but if commercial licensing is an obstacle, consider any of the free alternatives that support `compose v2`; Podman and Rancher Desktop are also solid choices. + +### Directions +1. Bring the environment up + + ```bash + docker compose up --wait + ``` +2. Open port 8001 in your browser http://localhost:8001 +3. Log in with the username `admin` and password `admin`. +4. Make your edits, and have fun! (SpiffWorkflow will make pull-requests to this repository on your behalf.) +5. Bring the environment down + ```bash + docker compose down + ``` + +### Troubleshooting + +__The files created by SpiffWorkflow are owned by root, making them hard to deal with. How can I resolve and prevent that?__ + +Resolve this by first changing the ownership of any existing root-owned files to match your local user. For example: + +```bash +$ sudo chown -R "$(id -u):$(id -g)" . +``` + +Prevent this in future by specifying the environment variable `RUN_AS` to indicate that you want SpiffWorkflow to create files owned by your local user. + +```bash +$ RUN_AS="$(id -u):$(id -g)" docker compose up --wait +``` + +You should probably set `RUN_AS` in the `.env` file, in your `.bashrc`, or some other local profile file so that you don't need to remember to specify it every time. + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4f3e096 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,86 @@ +# Derived from https://github.com/sartography/spiff-arena/blob/main/docker-compose.yml + +services: + spiffworkflow-frontend: + container_name: spiffworkflow-frontend + image: ghcr.io/sartography/spiffworkflow-frontend:latest + depends_on: + spiffworkflow-backend: + condition: service_started + environment: + APPLICATION_ROOT: "/" + PORT0: "${SPIFFWORKFLOW_FRONTEND_PORT:-8001}" + ports: + - "${SPIFFWORKFLOW_FRONTEND_PORT:-8001}:${SPIFFWORKFLOW_FRONTEND_PORT:-8001}/tcp" + + # Ensure that the RUN_AS user is able to write to the named volume where the sqlite DB will be + # Solution via https://stackoverflow.com/a/73255981 + match-volume-ownership: + container_name: match-volume-ownership + image: alpine + restart: "no" + entrypoint: | + /bin/sh -c "chown ${RUN_AS:-0:0} /app/db_volume" + volumes: + - spiffworkflow_backend_db:/app/db_volume:rw + + spiffworkflow-backend: + container_name: spiffworkflow-backend + image: ghcr.io/sartography/spiffworkflow-backend:main-latest + # Enable setting the ownership of created files to match the local user:group. For example: + # RUN_AS="$(id -u):$(id -g)" docker compose up -d + user: ${RUN_AS:-0:0} + depends_on: + match-volume-ownership: + condition: service_completed_successfully + environment: + SPIFFWORKFLOW_BACKEND_ENV: "local_docker" + FLASK_DEBUG: "0" + FLASK_SESSION_SECRET_KEY: "${FLASK_SESSION_SECRET_KEY:-super_secret_key}" + # WARNING: Frontend is a static site which assumes frontend port - 1 on localhost. + SPIFFWORKFLOW_BACKEND_URL: "http://localhost:${SPIFF_BACKEND_PORT:-8000}" + + SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR: "/app/process_models" + SPIFFWORKFLOW_BACKEND_CONNECTOR_PROXY_URL: "http://spiffworkflow-connector:8004" + SPIFFWORKFLOW_BACKEND_DATABASE_TYPE: "sqlite" + SPIFFWORKFLOW_BACKEND_DATABASE_URI: "sqlite:////app/db_volume/db.sqlite3" + SPIFFWORKFLOW_BACKEND_LOAD_FIXTURE_DATA: "false" + SPIFFWORKFLOW_BACKEND_LOG_LEVEL: "DEBUG" + SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_ID: "spiffworkflow-backend" + SPIFFWORKFLOW_BACKEND_OPEN_ID_CLIENT_SECRET_KEY: "my_open_id_secret_key" + SPIFFWORKFLOW_BACKEND_OPEN_ID_SERVER_URL: "http://localhost:${SPIFF_BACKEND_PORT:-8000}/openid" + SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME: "example.yml" + SPIFFWORKFLOW_BACKEND_PORT: "${SPIFF_BACKEND_PORT:-8000}" + SPIFFWORKFLOW_BACKEND_RUN_BACKGROUND_SCHEDULER_IN_CREATE_APP: "true" + SPIFFWORKFLOW_BACKEND_UPGRADE_DB: "true" + SPIFFWORKFLOW_BACKEND_URL_FOR_FRONTEND: "http://localhost:${SPIFFWORKFLOW_FRONTEND_PORT:-8001}" + ports: + - "${SPIFF_BACKEND_PORT:-8000}:${SPIFF_BACKEND_PORT:-8000}/tcp" + volumes: + - ${SPIFFWORKFLOW_BACKEND_LOCAL_BPMN_SPEC_DIR:-./process_models}:/app/process_models + - spiffworkflow_backend_db:/app/db_volume + healthcheck: + test: "curl localhost:${SPIFF_BACKEND_PORT:-8000}/v1.0/status --fail" + interval: 10s + timeout: 5s + retries: 20 + + spiffworkflow-connector: + container_name: spiffworkflow-connector + image: ghcr.io/sartography/connector-proxy-demo:latest + environment: + FLASK_ENV: "${FLASK_ENV:-development}" + FLASK_DEBUG: "0" + FLASK_SESSION_SECRET_KEY: "${FLASK_SESSION_SECRET_KEY:-super_secret_key}" + CONNECTOR_PROXY_PORT: "${SPIFF_CONNECTOR_PORT:-8004}" + ports: + - "${SPIFF_CONNECTOR_PORT:-8004}:${SPIFF_CONNECTOR_PORT:-8004}/tcp" + healthcheck: + test: "curl localhost:${SPIFF_CONNECTOR_PORT:-8004}/liveness --fail" + interval: 10s + timeout: 5s + retries: 20 + +volumes: + spiffworkflow_backend_db: + driver: local