Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
171 commits
Select commit Hold shift + click to select a range
476014b
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
9985b7d
Make NamedObject reusable
juztas Jan 15, 2026
bf82bcc
Include operation_id for facility (similar to pull request #21)
juztas Jan 15, 2026
75945e0
simplified facility endpoint proposal
gabor-lbl Jan 15, 2026
52567f2
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
0dbb6d8
Remove /api/v1
juztas Jan 15, 2026
65a4e46
Refactor shared validators & models to fix import loading issues
juztas Jan 20, 2026
f4adcb6
Github Action to validate api
juztas Jan 20, 2026
b3e96f7
Add custom get extra function
juztas Jan 20, 2026
5b4d7e2
Implement opentelemetry. Use UTC in demo adapter
juztas Jan 20, 2026
b697d18
Rename dependencies to common
juztas Jan 20, 2026
db5878c
Do not swallow exceptions
juztas Jan 21, 2026
df38b39
Ensure that computed fields are included in output
juztas Jan 22, 2026
a634c63
Code base compliant with the official Spec
juztas Jan 23, 2026
bca4945
Fully compliant with official spec
juztas Jan 23, 2026
a6bc9af
Enforce Py 3.14 as used release for everything
juztas Jan 23, 2026
8d830e0
Enable deepsource scanning
juztas Jan 23, 2026
f4914e8
Enforce consistent package versions (pin major/minor version)
juztas Jan 25, 2026
6a76580
Add minimum changes to support containers
cjh1 Nov 25, 2025
0f50a06
Add documentation
cjh1 Dec 4, 2025
ec3b448
Remove used import
cjh1 Feb 3, 2026
0618f2f
Merge pull request #8 from cjh1/containers
gabor-lbl Feb 3, 2026
09b409d
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
3e8b0b2
Make NamedObject reusable
juztas Jan 15, 2026
cf79917
Include operation_id for facility (similar to pull request #21)
juztas Jan 15, 2026
0d68a1c
simplified facility endpoint proposal
gabor-lbl Jan 15, 2026
ed6befa
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
28e5ba7
Remove /api/v1
juztas Jan 15, 2026
e8d256b
Refactor shared validators & models to fix import loading issues
juztas Jan 20, 2026
58b9ef8
Github Action to validate api
juztas Jan 20, 2026
bc55843
Add custom get extra function
juztas Jan 20, 2026
75a5cb6
Implement opentelemetry. Use UTC in demo adapter
juztas Jan 20, 2026
be30570
Rename dependencies to common
juztas Jan 20, 2026
6b85fbf
Do not swallow exceptions
juztas Jan 21, 2026
952aea0
Ensure that computed fields are included in output
juztas Jan 22, 2026
a1c4e53
Code base compliant with the official Spec
juztas Jan 23, 2026
6fb8e8b
Fully compliant with official spec
juztas Jan 23, 2026
53bc4c3
Enforce Py 3.14 as used release for everything
juztas Jan 23, 2026
846c1f8
Enable deepsource scanning
juztas Jan 23, 2026
2374d34
Enforce consistent package versions (pin major/minor version)
juztas Jan 25, 2026
cba88c2
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
6f44f67
Make NamedObject reusable
juztas Jan 15, 2026
fbab525
Include operation_id for facility (similar to pull request #21)
juztas Jan 15, 2026
7ca9b75
simplified facility endpoint proposal
gabor-lbl Jan 15, 2026
936cf35
Add Facility API, demo data, stricter query validation and /api/v1 di…
juztas Jan 12, 2026
58d5602
Remove /api/v1
juztas Jan 15, 2026
630cd61
Refactor shared validators & models to fix import loading issues
juztas Jan 20, 2026
2cf089b
Github Action to validate api
juztas Jan 20, 2026
ea013e2
Add custom get extra function
juztas Jan 20, 2026
9eb22d9
Implement opentelemetry. Use UTC in demo adapter
juztas Jan 20, 2026
a23407e
Rename dependencies to common
juztas Jan 20, 2026
85c8e76
Do not swallow exceptions
juztas Jan 21, 2026
29b6ff0
Ensure that computed fields are included in output
juztas Jan 22, 2026
94094de
Code base compliant with the official Spec
juztas Jan 23, 2026
9c2eb9e
Fully compliant with official spec
juztas Jan 23, 2026
2bd894c
Enforce Py 3.14 as used release for everything
juztas Jan 23, 2026
21c03ca
Enable deepsource scanning
juztas Jan 23, 2026
6cb85bf
Enforce consistent package versions (pin major/minor version)
juztas Jan 25, 2026
6ccddc7
Make adapter forward compatible. add filtering, pagination, datetime …
juztas Feb 3, 2026
ccfd2fe
Remove kwargs (versioning agreed)
juztas Feb 4, 2026
1206be9
get_resource single id
juztas Feb 4, 2026
1c78ca6
Merge branch 'main' into kwargslint
juztas Feb 4, 2026
ac96466
Merge branch 'main' into kwargslint
juztas Feb 5, 2026
b141dbd
Add paginate in demo_adapter. Fix number of params for override method
juztas Feb 5, 2026
ef5c6e2
Harden validation and response allingment with spec
juztas Feb 5, 2026
2040b48
Update Facility endpoint (based on new Format discussed during the me…
juztas Feb 5, 2026
e85c266
Fix operation id: getJob, getJobs
juztas Feb 5, 2026
431da63
Remove resource_uri and event_uris
juztas Feb 5, 2026
8892724
Remove resource_uri and event_uris
juztas Feb 5, 2026
f9ee205
Merge branch 'main' into kwargslint
juztas Feb 6, 2026
57592f1
Merge pull request #27 from doe-iri-esnet/main
gabor-lbl Feb 6, 2026
3273b8a
Add site_id under resource. Fix schemathesis run with excluding none …
juztas Feb 7, 2026
68a72bc
Split common.py into it's own types
juztas Feb 7, 2026
41b3400
Merge pull request #1 from juztas/kwargslint
juztas Feb 7, 2026
4d11d60
Merge pull request #29 from doe-iri-esnet/main
gabor-lbl Feb 7, 2026
9e65878
ruff, lint, bandit, pip-audit all codebase. Update Makefile to allow
juztas Feb 7, 2026
f721ab1
Add response exclude none. Esnet endpoint fails validation with none …
juztas Feb 9, 2026
938409d
Merge pull request #30 from doe-iri-esnet/pylintaudit
gabor-lbl Feb 9, 2026
117b96e
Changed site_url to site_id
gabor-lbl Feb 9, 2026
8ff1039
Merge pull request #32 from doe-iri/site_id
gabor-lbl Feb 9, 2026
346cf0d
the facility api doesn't require authentication
gabor-lbl Feb 9, 2026
9d47023
Merge pull request #33 from doe-iri/facility_abc
gabor-lbl Feb 9, 2026
2cd36d0
updated api endpoint url for NERSC
gabor-lbl Feb 9, 2026
3b3651f
minor readme update
gabor-lbl Feb 10, 2026
821a681
Facility api fix in case the adapter returns null
gabor-lbl Feb 11, 2026
1953879
hide facility/ from swagger
gabor-lbl Feb 11, 2026
f7839e0
Merge pull request #34 from doe-iri/facility_fix
gabor-lbl Feb 11, 2026
d55147d
Task Improvements (response format, task_uri, fix get_resource call)
juztas Feb 16, 2026
8d4f0af
Do not swallow error message returned by backend driver. Pass it back…
juztas Feb 17, 2026
f26c6de
Use TaskSubmitResponse for rm
juztas Feb 17, 2026
a9773fe
Merge pull request #37 from juztas/errswal
gabor-lbl Feb 17, 2026
3cbaf96
Merge pull request #36 from juztas/tasksubmit
gabor-lbl Feb 17, 2026
8a7a743
minor bugfix
gabor-lbl Feb 17, 2026
da54e0c
RFC 7807 OpenAPI native error modeling
juztas Feb 17, 2026
594d758
Add servers url inside the spec
juztas Feb 18, 2026
341c557
Fixes while implementing filesystem for ESnet endpoint
juztas Feb 18, 2026
730b740
Include last_modified and self_uri in Projects. As required by offici…
juztas Feb 18, 2026
fffeb68
Filesystem validation and fixes (pyhumps, aliasChoices, testscript
juztas Feb 19, 2026
5f5c6c3
RFC 9457 compliant
juztas Feb 19, 2026
f55cb80
RFC9457 and consistent with Java expectations
juztas Feb 20, 2026
b2a5c29
Everything is snake_case for fs operations
juztas Feb 20, 2026
35620b7
Merge pull request #38 from juztas/rfc7807
gabor-lbl Feb 20, 2026
2233c7b
Merge pull request #39 from juztas/fsfixes
gabor-lbl Feb 20, 2026
42cea9f
OpenAPI 3.1 update (doc, anyOf remove). Logger, DemoAdapter upd
juztas Feb 23, 2026
3308337
Downgrade to py313
juztas Feb 23, 2026
822af94
Remove unsupported operand. Py3.13 vs 3.14
juztas Feb 23, 2026
f7d685f
Merge pull request #41 from juztas/313py
juztas Feb 23, 2026
98f3dc6
Dummy force retest
juztas Feb 23, 2026
9d85368
Merge pull request #40 from juztas/openapiupd
gabor-lbl Feb 23, 2026
3c36765
Update fs test script. Print all resources and provide option to choo…
juztas Feb 25, 2026
052c583
Merge pull request #42 from juztas/main
juztas Feb 25, 2026
da6f0be
Remove offset from head/tail calls. This info is already present in t…
gabor-lbl Feb 25, 2026
5ad3401
Merge pull request #44 from doe-iri/offset
gabor-lbl Feb 26, 2026
a8fa143
use bearer tokens
gabor-lbl Feb 27, 2026
fffbdd7
Merge pull request #45 from doe-iri/bearer
gabor-lbl Feb 27, 2026
60aaf0e
restore null-s to models/endpoints that can be null. This is needed t…
gabor-lbl Feb 25, 2026
c43431b
removed or-none from Query args
gabor-lbl Feb 25, 2026
414548a
Merge pull request #43 from doe-iri/or_none
gabor-lbl Feb 27, 2026
0a5ddd2
Tighten query types and handle empty retsults with 404
juztas Mar 2, 2026
7a2c871
Fix schemathesis errors
juztas Mar 2, 2026
5d924ba
Do not use Any in return
juztas Mar 2, 2026
6b56ffa
Fix FS Demo adapter to return in json
juztas Mar 3, 2026
f31ff76
view to use FileContent to return output
gabor-lbl Mar 3, 2026
40cca55
Merge pull request #48 from doe-iri/view
gabor-lbl Mar 3, 2026
2f4d37a
Merge pull request #46 from juztas/nonedef
gabor-lbl Mar 3, 2026
b694b52
renamed incorrectly named param
gabor-lbl Mar 4, 2026
74e3fce
Merge pull request #56 from doe-iri/tail_fix
gabor-lbl Mar 4, 2026
86c0f90
Change object to dict
juztas Mar 4, 2026
b0f50b8
on_task bugfix. Refs https://github.com/doe-iri/iri-facility-api-pyth…
gabor-lbl Mar 4, 2026
623e207
handle both dict and BaseModel
gabor-lbl Mar 4, 2026
0bd74e3
Merge pull request #58 from doe-iri/task_fix
gabor-lbl Mar 4, 2026
c762036
JobSpec is used as both input and output model. Refs https://github.c…
gabor-lbl Mar 4, 2026
92e5dc5
Merge pull request #47 from juztas/anyoffix
gabor-lbl Mar 4, 2026
23af870
use default_factory for list/dict params
gabor-lbl Mar 5, 2026
eaab4cc
Merge pull request #59 from doe-iri/jobspec2
gabor-lbl Mar 6, 2026
0d8d8e9
make events a top level object
gabor-lbl Mar 9, 2026
3d88afb
removed upper limit on offset param
gabor-lbl Mar 10, 2026
8c1a3b2
Merge pull request #61 from doe-iri/events
gabor-lbl Mar 10, 2026
5001957
held job state
gabor-lbl Mar 10, 2026
600f985
globus integration
gabor-lbl Mar 13, 2026
96a7eee
globus integration
gabor-lbl Mar 13, 2026
15b00b8
exp and nbf checks
gabor-lbl Mar 16, 2026
626f05e
added missing file
gabor-lbl Mar 17, 2026
0c8dd79
logging and token splitting
gabor-lbl Mar 17, 2026
a52d79b
remove primary identity hack
gabor-lbl Mar 17, 2026
2511b2e
pass entire introspection result to facility + exception if session_i…
gabor-lbl Mar 19, 2026
cd0c643
Merge pull request #64 from doe-iri/globus
gabor-lbl Mar 19, 2026
562b33d
Add x-iri meta extra
juztas Mar 13, 2026
eb55c60
Use new labels same as DoE reporting
juztas Mar 18, 2026
c3b4fe2
change example label
juztas Mar 18, 2026
9455d9a
Update schema URL in API validation workflow
juztas Mar 19, 2026
0db75b7
removed /incidents/incident_id from event uris
Mar 19, 2026
5e7889f
Merge pull request #66 from doe-iri/event_uri_fix
juztas Mar 20, 2026
5d4958d
Merge pull request #60 from juztas/irimature
juztas Mar 20, 2026
aca8a20
Auth Once at the FastAPI Level
juztas Mar 23, 2026
49ff4fd
Add user type
juztas Mar 23, 2026
93878dd
force login so session_info.authentications is not empty
gabor-lbl Mar 24, 2026
e111143
Merge pull request #68 from juztas/authonce
juztas Mar 24, 2026
9f29795
Merge pull request #69 from doe-iri/force_login
gabor-lbl Mar 24, 2026
8a1e065
Set Compute, Filesystem, Task to Production status
juztas Mar 31, 2026
4e5745f
Pass Error Message back of failed auth
juztas Mar 31, 2026
8fb98a4
More clear error message for missing session info
juztas Mar 31, 2026
1ef0513
Merge pull request #71 from juztas/PassErrMsg
juztas Apr 1, 2026
c1e77f5
Merge pull request #70 from juztas/v100
juztas Apr 1, 2026
7667d95
[Feat] Dynamic URI generated from forwarded headers (Kong, Nginx,...)
juztas Apr 2, 2026
d5a6c56
default historical now True by default for get_job
Apr 9, 2026
392dcd2
Merge pull request #74 from doe-iri/historical-true-for-get-job
pmrich Apr 9, 2026
a6fcf7e
Merge pull request #72 from juztas/dynamicuri
juztas Apr 22, 2026
1083f2a
merging upstream doe-iri repo updates
May 3, 2026
2cee544
worked through integration issues as a result of upstream merge
May 4, 2026
fd81bab
removed changes to compute.py
May 4, 2026
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
9 changes: 9 additions & 0 deletions .deepsource.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version = 1

[[analyzers]]
name = "python"
enabled = true

[analyzers.meta]
runtime_version = "3.x.x"
max_line_length = 200
132 changes: 132 additions & 0 deletions .github/workflows/api-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: API Validation with Schemathesis

on:
pull_request:
push:
branches: [ main ]

jobs:
schemathesis:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Checkout schema validator repository
uses: actions/checkout@v4
with:
repository: doe-iri/iri-facility-api-docs
ref: main
path: schema-validator
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install uv
run: pip install uv

- name: Build an image
run: docker build --platform=linux/amd64 -t iri-facility-api-base .

- name: Run Facility API container
run: |
docker run -d \
-p 8000:8000 \
--platform=linux/amd64 \
--name iri-facility-api-base \
-e IRI_API_ADAPTER_facility=app.demo_adapter.DemoAdapter \
-e IRI_API_ADAPTER_status=app.demo_adapter.DemoAdapter \
-e IRI_API_ADAPTER_account=app.demo_adapter.DemoAdapter \
-e IRI_API_ADAPTER_compute=app.demo_adapter.DemoAdapter \
-e IRI_API_ADAPTER_filesystem=app.demo_adapter.DemoAdapter \
-e IRI_API_ADAPTER_task=app.demo_adapter.DemoAdapter \
-e API_URL_ROOT=http://127.0.0.1:8000 \
-e IRI_API_TOKEN=12345 \
iri-facility-api-base

- name: Wait for API to be ready
run: |
for i in {1..60}; do
if curl -fs http://127.0.0.1:8000/openapi.json; then
echo "API ready"
exit 0
fi
sleep 2
done
echo "API did not start"
exit 1

- name: Create venv & install validator dependencies
run: |
uv venv
source .venv/bin/activate
uv pip install -r schema-validator/verification/requirements.txt

- name: Run Schemathesis validation (local spec)
id: schemathesis_local
env:
IRI_API_TOKEN: "12345" # This is dummy token for testing (mock adapter)
run: |
set +e
source .venv/bin/activate
python schema-validator/verification/api-validator.py \
--baseurl http://127.0.0.1:8000 \
--report-name schemathesis-local
echo "exitcode=$?" >> $GITHUB_OUTPUT

- name: Run Schemathesis validation (official spec)
id: schemathesis_official
env:
IRI_API_TOKEN: "12345"
run: |
set +e
source .venv/bin/activate
python schema-validator/verification/api-validator.py \
--baseurl http://localhost:8000 \
--schema-url https://raw.githubusercontent.com/doe-iri/iri-facility-api-docs/refs/heads/main/specification/openapi/all_spec.yaml \
--report-name schemathesis-official
echo "exitcode=$?" >> $GITHUB_OUTPUT

- name: Fail if any Schemathesis run failed
if: always()
run: |
if [ "${{ steps.schemathesis_local.outputs.exitcode }}" != "0" ] || \
[ "${{ steps.schemathesis_official.outputs.exitcode }}" != "0" ]; then
echo "One or more Schemathesis validations failed"
exit 1
else
echo "Both Schemathesis validations passed"
fi

- name: Upload Schemathesis report # This only works on git actions
if: always() && env.ACT != 'true'
uses: actions/upload-artifact@v4
with:
if-no-files-found: warn
name: schemathesis-report
path: |
schemathesis-local.html
schemathesis-local.xml
schemathesis-official.html
schemathesis-official.xml

- name: Save Schemathesis reports locally # This only works if run locally with act
if: always() && env.ACT == 'true'
run: |
mkdir -p artifacts
cp schemathesis-local.html schemathesis-local.xml artifacts/ || true
cp schemathesis-official.html schemathesis-official.xml artifacts/ || true

- name: Dump API logs
if: always()
run: docker logs iri-facility-api-base || true

- name: Stop container
if: always()
run: docker stop iri-facility-api-base || true
5 changes: 2 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ iri_sandbox
.env
uv.lock
docs/
Makefile
pyproject.toml
.DS_Store
data/
app/s3df/coact-models.py
Expand All @@ -16,4 +14,5 @@ app/s3df/clients/IMPLEMENTATION.md
set_env.sh
test_compute.sh
fastapi.log
compute-tests/
compute-tests/
local.env
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.13-slim
FROM python:3.13

RUN mkdir /app
COPY . /app
Expand All @@ -14,4 +14,3 @@ ENV DEX_ISSUER="https://dex.slac.stanford.edu"


CMD ["fastapi", "run", "app/main.py", "--port", "8000"]

103 changes: 80 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,47 +1,104 @@
dev : .venv
@source ./.venv/bin/activate && \
IRI_API_ADAPTER_status=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_account=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_compute=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_filesystem=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_task=app.demo_adapter.DemoAdapter \
API_URL_ROOT='http://127.0.0.1:8000' fastapi dev
PYTHON := python3.13
VENV := .venv
BIN := $(VENV)/bin
UV := uv
PIP := $(BIN)/pip

STAMP_VENV := $(VENV)/.created
STAMP_DEPS := $(VENV)/.deps

dev-s3df : .venv
@source ./.venv/bin/activate && \
IRI_API_ADAPTER_account=app.s3df.account_adapter.S3DFAccountAdapter \
COACT_API_URL='https://coact-dev.slac.stanford.edu/graphql-service-dev' \
IRI_SHOW_MISSING_ROUTES='true' \
API_URL_ROOT='http://127.0.0.1:8000' fastapi dev
.DEFAULT_GOAL := dev

$(STAMP_VENV):
$(UV) venv $(VENV)
touch $(STAMP_VENV)

.venv: $(STAMP_VENV)

$(STAMP_DEPS): $(STAMP_VENV) pyproject.toml
$(UV) pip install --python $(BIN)/python -e .
$(UV) pip install --python $(BIN)/python \
ruff \
pylint \
bandit
touch $(STAMP_DEPS)

deps: $(STAMP_DEPS)

dev: deps
@source $(BIN)/activate && \
[ -f local.env ] && source local.env || true && \
IRI_API_ADAPTER_facility=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_status=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_account=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_compute=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_filesystem=app.demo_adapter.DemoAdapter \
IRI_API_ADAPTER_task=app.demo_adapter.DemoAdapter \
DEMO_QUEUE_UPDATE_SECS=2 \
OPENTELEMETRY_ENABLED=true \
API_URL_ROOT='http://localhost:8000' fastapi dev

dev-s3df: deps
@source $(BIN)/activate && \
IRI_API_ADAPTER_account=app.s3df.account_adapter.S3DFAccountAdapter \
COACT_API_URL='https://coact-dev.slac.stanford.edu/graphql-service-dev' \
IRI_SHOW_MISSING_ROUTES='true' \
API_URL_ROOT='http://127.0.0.1:8000' fastapi dev

# --- Docker / GHCR targets ---
GHCR_USERNAME ?= ""
GHCR_IMAGE ?= ghcr.io/$(GHCR_USERNAME)/iri-s3df
IMAGE_TAG ?= dev

# build for linux/amd64 (for now, since coact client only works on linux)
docker-build:
docker build --platform linux/amd64 -t $(GHCR_IMAGE):$(IMAGE_TAG) .

docker-push: docker-build
docker push $(GHCR_IMAGE):$(IMAGE_TAG)

# Test coact client locally inside the container (needs password)
docker-test-coact:
@docker run --rm -it \
-e COACT_SERVICE_PASSWORD \
$(GHCR_IMAGE):$(IMAGE_TAG) \
python -m app.s3df.clients.example

.PHONY: clean
clean:
rm -rf iri_sandbox
rm -rf .venv

.venv:
@uv venv
@uv pip install -e .
# Format and lint
format: deps
$(BIN)/ruff format --line-length 200 .

ruff: deps
$(BIN)/ruff check . --fix || true

.PHONY: clean
clean:
@rm -rf iri_sandbox
@rm -rf .venv
pylint: deps
find . -path ./$(VENV) -prune -o -type f -name "*.py" -print0 | while IFS= read -r -d '' f; do \
echo "Pylint $$f"; \
$(BIN)/pylint $$f --rcfile pylintrc || true; \
done

# Security
audit: deps
uv pip compile pyproject.toml -o requirements.txt
uv pip sync requirements.txt
uv pip install pip-audit
$(BIN)/pip-audit || true
rm -f requirements.txt

bandit: deps
$(BIN)/bandit -r app || true

# Full validation bundle
lint: clean format ruff pylint audit bandit

globus: deps
@source local.env && $(BIN)/python ./tools/globus.py

ARGS ?=

# call it via: make manage-globus ARGS=scopes-show
manage-globus: deps
@source local.env && $(BIN)/python ./tools/manage_globus.py $(ARGS)
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ See it live:

- NERSC instance:
- API docs: https://api.iri.nersc.gov
- API requests: https://api.iri.nersc.gov/nersc/api/v1/
- API requests: https://api.iri.nersc.gov/api/v1/
- ALCF instance:
- API docs: https://api.alcf.anl.gov
- API requests: https://api.alcf.anl.gov/api/v1/
Expand Down Expand Up @@ -51,6 +51,8 @@ If using docker (see next section), your dockerfile could extend this reference
- `API_URL_ROOT`: the base url when constructing links returned by the api (eg.: https://iri.myfacility.com)
- `API_PREFIX`: the path prefix where the api is hosted. Defaults to `/`. (eg.: `/api`)
- `API_URL`: the path to the api itself. Defaults to `api/v1`.
- `OPENTELEMETRY_ENABLED`: Enables OpenTelemetry. If enabled, the application will use OpenTelemetry SDKs and emit traces, metrics, and logs. Default to false
- `OTLP_ENDPOINT`: OpenTelemetry Protocol collector endpoint to export telemetry data. If empty or not set, telemetry data is logged locally to log file. Default: ""

Links to data, created by this api, will concatenate these values producing links, eg: `https://iri.myfacility.com/my_api_prefix/my_api_url/projects/123`

Expand Down Expand Up @@ -119,11 +121,25 @@ ENV IRI_API_PARAMS='{ \
}'
```

## Globus auth integration

You can optionally use globus for authorization. Steps to use globus:
- ask someone to add your globus account to the IRI Resource Server
- log into globus and make a secret for yourself for the IRI Resource Server
- if you want to create tokens during developent, also create a separate globus app
- `cp local-template.env local.env` and fill in the missing values
- to mint a token, run `make globus`, click the link and copy the code from the browser url bar back into the terminal
- you can also run `make manage-globus` but be sure to not accidentally delete the `iri-api` scope. (Maybe it's better if you don't run this app)
- now you can run `make` for the dev server and enjoy using your globus iri access tokens (in the demo adapter they will all resolve to the user `gtorok`)
- for your facility:
- implement the `get_current_user_globus` method (see iri_adapter.py). Here you can look at the linked globus identities and session info to determine what the local username is
- make sure the values in `local.env` are available in the deployed app

## Next steps

- Learn more about [fastapi](https://fastapi.tiangolo.com/), including how to run it [in production](https://fastapi.tiangolo.com/advanced/behind-a-proxy/)
- Instead of the simulated state, keep real data in a [database](/Users/gtorok/dev/iri-api-python/README.md)
- Add monitoring by [integrating with OpenTelemetry](https://opentelemetry.io/docs/zero-code/python/)
- Instead of the simulated state, keep real data in a database
- Specify the monitoring endpoint by setting the [OpenTelemetry](https://opentelemetry.io/docs/zero-code/python/) env vars
- Add additional routers for other API-s
- Add authenticated API-s via an [OAuth2 integration](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/)

5 changes: 3 additions & 2 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
from pkgutil import extend_path

__path__ = extend_path(__path__, __name__)
28 changes: 28 additions & 0 deletions app/apilogger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Logging utilities for the IRI Facility API."""
import logging

LEVELS = {"FATAL": logging.FATAL,
"ERROR": logging.ERROR,
"WARNING": logging.WARNING,
"INFO": logging.INFO,
"DEBUG": logging.DEBUG}


def get_stream_logger(name: str = __name__, level: str = "DEBUG") -> logging.Logger:
"""
Return a configured Stream logger.
"""
logger = logging.getLogger(name)

if not logger.handlers:
handler = logging.StreamHandler()

formatter = logging.Formatter("%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s", datefmt="%a, %d %b %Y %H:%M:%S")

handler.setFormatter(formatter)
logger.addHandler(handler)

logger.setLevel(LEVELS.get(level, logging.DEBUG))
logger.propagate = False

return logger
Loading
Loading