Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
572a56a
ci(deploy): SKIP_DEV_TESTS repo variable skips the dev test gates
saqibmanan Oct 9, 2026
2f5f925
ci(deploy): manual rollback button for dev
saqibmanan Oct 9, 2026
a254a05
Merge pull request #241 from CivicDataLab/ci-dev-test-skip-flag
saqibmanan Oct 9, 2026
df34e5a
fix(api): point PUBLIC_API_URL fallback at the live prod API
anantjain341 Oct 12, 2026
b884240
Merge pull request #244 from anantjain341/fix/public-api-url-fallback
anantjain341 Oct 12, 2026
b66f511
fix(api): stop returning exception text from metadata export
anantjain341 Oct 12, 2026
8dd95b7
Merge pull request #245 from anantjain341/fix/export-error-exposure
anantjain341 Oct 12, 2026
0aed488
add network override for docker hotreload
amit0539 Oct 12, 2026
5a5bc26
add AGENTS.md
amit0539 Oct 12, 2026
e9d458b
Merge branch 'dev' into s3_migration
amit0539 Oct 12, 2026
e4c52db
refactor(api)!: remove DVC dataset versioning
amit9838 Oct 19, 2026
0473100
feat(storage): add S3 public/private media storages
amit9838 Oct 19, 2026
73f5381
feat(storage): store model file fields in S3
amit9838 Oct 19, 2026
85e1833
fix(api): read and serve media without local file paths
amit9838 Oct 19, 2026
1eb56a3
feat(api): redirect legacy /public media links to S3
amit9838 Oct 19, 2026
a1ef6f9
feat(api): add migrate_media_to_s3 command
amit9838 Oct 19, 2026
df06b6a
test(api): cover the move to S3-only media
amit9838 Oct 19, 2026
062eed7
docs: describe S3-only media storage
amit9838 Oct 19, 2026
fa89bfa
docs: expand AGENTS.md with setup, checklists and media rules
amit9838 Oct 19, 2026
f8d747a
feat(metadata): add source identifier dataset metadata item
psaesha Oct 21, 2026
f84edbf
Merge pull request #250 from CivicDataLab/feat/scrapers/source-identi…
anantjain341 Oct 22, 2026
a74e2e9
feat(api): table queries for use cases, collaboratives, AI models, pu…
anantjain341 Oct 22, 2026
4b57735
refactor(api): datasetsTable uses the shared status_counts helper
anantjain341 Oct 22, 2026
3143e40
Merge pull request #254 from anantjain341/feat/listing-tables
anantjain341 Oct 22, 2026
6842cbf
feat(api): add chartsTable with filters, sorting and pagination
anantjain341 Oct 27, 2026
bf8e275
refactor(api): page chartsTable through get_pagination_window
anantjain341 Oct 27, 2026
113894c
Merge pull request #262 from anantjain341/feat/charts-table
anantjain341 Oct 27, 2026
43d7eef
feat(api): add Event model and GraphQL schema for event management
Abhishekfm Oct 28, 2026
f1fe234
fix(api): match isIndividualEvent to the Event model rule
anantjain341 Oct 28, 2026
b2fae58
feat(api): permanent public links for events
anantjain341 Oct 29, 2026
5a8eb32
fix(api): drop missing 0049 dependency from 0055_event
anantjain341 Oct 29, 2026
7bee5e5
refactor(api): fold event public_id into 0055 and drop Event.slug
anantjain341 Oct 29, 2026
34d75db
Merge pull request #264 from anantjain341/feat/event-public-links
anantjain341 Oct 29, 2026
11a0f8d
Merge pull request #263 from CivicDataLab/feat-events
anantjain341 Oct 29, 2026
9f16248
fix(api): add permission checks to dataset resources, charts and acce…
anantjain341 Oct 29, 2026
e1f6d63
refactor(api): share one dataset edit rule and limit organisation lis…
anantjain341 Oct 29, 2026
ba39243
test(api): cover dataset, resource, chart and access model permissions
anantjain341 Oct 30, 2026
2abfa6a
feat(api): offer every license in licenses.csv as a DatasetLicense ch…
amit0539 Oct 31, 2026
19f38f2
fix(api): map SPDX license ids from imported datasets instead of defa…
amit0539 Oct 31, 2026
fef6a1b
Merge pull request #269 from CivicDataLab/update-license-list
amit0539 Nov 2, 2026
d99454a
feat(api): add event search with filters and pagination
anantjain341 Nov 2, 2026
04c186f
Merge pull request #270 from anantjain341/feat/event-search
anantjain341 Nov 2, 2026
4a38e32
fix(ci): create the event search index on deploy
anantjain341 Nov 2, 2026
2ed325b
Merge pull request #271 from anantjain341/fix/deploy-event-index
anantjain341 Nov 2, 2026
59fe950
fix(api): rebuild the event search index once if it has guessed types
anantjain341 Nov 2, 2026
110d9b5
Merge pull request #272 from anantjain341/fix/repair-event-index
anantjain341 Nov 2, 2026
4d2ef05
Merge branch 'dev' into s3_migration
amit0539 Nov 3, 2026
cb41adb
Merge branch 'dev' into s3_migration
amit0539 Nov 3, 2026
69424d5
Merge branch 'dev' into s3_migration
amit0539 Nov 3, 2026
5a7f55a
fix migrations
amit0539 Nov 3, 2026
42bfef4
Merge pull request #249 from CivicDataLab/s3_migration
saqibmanan Nov 3, 2026
4d90ade
fix(ci): pass STORAGE_* vars to the image sanity check
saqibmanan Nov 3, 2026
9f3d9e6
Merge pull request #274 from CivicDataLab/fix/ci-sanity-check-storage…
saqibmanan Nov 3, 2026
f2f18c3
feat(api): add Luma cover image to event search results
anantjain341 Nov 3, 2026
b729850
Merge pull request #275 from anantjain341/feat/event-cover-image
anantjain341 Nov 3, 2026
30a851d
feat(api): permanent public links for all modules
anantjain341 Nov 2, 2026
3c964ba
feat(api): take publicId on every public page query
anantjain341 Nov 2, 2026
8c13f59
fix(api): keep collaborative slugs unique, they are also the subdomain
anantjain341 Nov 2, 2026
8cc1453
chore(api): renumber public link migrations after dev's 0059
anantjain341 Nov 3, 2026
0cf7ee8
Merge pull request #273 from anantjain341/feat/public-links-all-modules
anantjain341 Nov 3, 2026
4434973
fix(api): stop same-name uploads failing on the resource slug rule
anantjain341 Nov 4, 2026
4ddee76
don't index summary for now
amit0539 Nov 4, 2026
aaea374
Merge pull request #277 from CivicDataLab/s3_migration
amit0539 Nov 4, 2026
335d1c1
fix(search): index long text fields without single-token sub-fields
amit0539 Nov 4, 2026
ede88c2
Merge pull request #278 from CivicDataLab/fix-elastic-search
amit0539 Nov 4, 2026
a50c514
Merge branch 'main' into fix-elastic-search
amit0539 Nov 4, 2026
95c985e
Merge pull request #280 from CivicDataLab/fix-elastic-search
amit0539 Nov 4, 2026
0885cef
Merge pull request #276 from anantjain341/fix/resource-slug-race
anantjain341 Nov 4, 2026
657457f
fix(search): rebuild indexes that still have single-token long text c…
anantjain341 Nov 4, 2026
548aac3
Merge pull request #281 from anantjain341/fix/search-long-text-reindex
anantjain341 Nov 4, 2026
064029f
Merge dev into fix/resource-permissions
anantjain341 Nov 5, 2026
1af5d91
Merge pull request #267 from anantjain341/fix/resource-permissions
anantjain341 Nov 5, 2026
c93fe23
Merge main into dev: bring in the long summary hotfix (#283)
anantjain341 Nov 5, 2026
fb30758
Merge pull request #286 from CivicDataLab/chore/backmerge-search-hotfix
anantjain341 Nov 5, 2026
c634d13
fix(data-api): read tables whose column names contain a percent sign
psaesha Nov 13, 2026
f4b743d
ci: pass test accounts 3-5 to the CivicDataSpace-test smoke workflow
saqibmanan Nov 13, 2026
a20e300
Merge pull request #295 from CivicDataLab/fix/percent-in-column-names
psaesha Nov 13, 2026
87baaba
feat(data-index): give every upload its own table and switch over safely
psaesha Nov 13, 2026
33c7755
feat(data-index): add migrate_data_table_names for existing tables
psaesha Nov 14, 2026
599b848
docs(data-index): add the data index architecture doc and runbook
psaesha Nov 14, 2026
b4bb21f
fix(data-index): keep the new table when a run stops after the switch
psaesha Nov 14, 2026
0e339eb
docs(data-index): mark the cut-column-name collision as a known TODO
psaesha Nov 14, 2026
da79551
docs(data-index): mark the silent failed re-upload as a known TODO
psaesha Nov 14, 2026
0dc798b
ci(sdk): run the SDK tests on ubuntu-24.04
psaesha Nov 14, 2026
d5ab75a
Merge pull request #298 from CivicDataLab/feature/data-index-table-names
psaesha Nov 14, 2026
4441862
ci: run provider tests in the dev deploy gate again
saqibmanan Nov 14, 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
19 changes: 11 additions & 8 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ GITHUB_TOKEN=

# URLs written into exported metadata (DCAT / Croissant); set per environment
PUBLIC_SITE_URL=https://civicdataspace.in
PUBLIC_API_URL=https://api.civicdataspace.in
PUBLIC_API_URL=https://api.datakeep.civicdays.in

# --- s3 only ---
# STORAGE_BUCKET=dataspace-dev
# STORAGE_REGION=ap-south-1
# STORAGE_ENV=dev
# STORAGE_PUBLIC_BASE_URL=
# STORAGE_ACCESS_KEY_ID=
# STORAGE_SECRET_ACCESS_KEY=
# Media storage (S3 only; required). STORAGE_ENV prefixes every key: use
# "local" for local development against the dev bucket. Leave the access keys
# empty on ECS/EC2 so the task role is used. STORAGE_PUBLIC_BASE_URL is the
# base for public asset URLs (CDN or bucket URL); empty uses the S3 bucket URL.
STORAGE_BUCKET=dataspace-dev
STORAGE_REGION=ap-south-1
STORAGE_ENV=local
STORAGE_PUBLIC_BASE_URL=
STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=

# Per-IP request throttling (api/middleware/rate_limit.py). False on dev only.
RATE_LIMIT_ENABLED=True
47 changes: 41 additions & 6 deletions .github/workflows/deploy-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ on:
type: boolean
required: false
default: false
rollback:
description: "Roll dev back to the image that was live before the last deploy (no build, no tests). Ignored on main."
type: boolean
required: false
default: false

# Queue overlapping deploys to the SAME environment rather than cancelling (a
# cancelled run mid-deploy could leave .deploy/ state and the running
Expand All @@ -82,6 +87,7 @@ env:
jobs:
build:
name: Build and push image
if: ${{ !inputs.rollback }}
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
Expand Down Expand Up @@ -179,6 +185,9 @@ jobs:
-e SECRET_KEY=ci-sanity-check-not-a-real-key \
-e URL_WHITELIST=http://localhost \
-e DB_ENGINE=django.db.backends.sqlite3 \
-e STORAGE_BUCKET=ci-sanity-check \
-e STORAGE_REGION=ap-south-1 \
-e STORAGE_ENV=ci \
--entrypoint python \
"${{ steps.ref.outputs.image_ref }}" \
manage.py check; then
Expand Down Expand Up @@ -250,6 +259,9 @@ jobs:
smoke-tests:
name: Smoke Tests
needs: deploy
# Repo variable SKIP_DEV_TESTS=true skips the dev test gates (e.g. while the
# test owner is away). main ignores it: prod deploys are always gated.
if: github.ref_name == 'main' || vars.SKIP_DEV_TESTS != 'true'
# No `environment:` here -- GitHub rejects the entire workflow file at
# parse time if a `uses:` job declares one. Consequence: this job also
# cannot see environment-scoped vars, which is why api_base_url comes
Expand All @@ -262,7 +274,6 @@ jobs:
# force_smoke_failure test path.
deployed_sha: ${{ (inputs.force_smoke_failure == true && 'forced-failure-sentinel') || github.sha }}
min_passed: ${{ inputs.force_smoke_failure && 999 || 1 }}
skip_provider: true
# main: only the readonly allowlist ever runs against prod.
# dev: stage 1 of 2 -- functional-tests runs only if this passes.
suite: ${{ github.ref_name == 'main' && 'readonly' || 'smoke' }}
Expand All @@ -276,6 +287,12 @@ jobs:
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
TEST_EMAIL_4: ${{ secrets.TEST_EMAIL_4 }}
TEST_PASSWORD_4: ${{ secrets.TEST_PASSWORD_4 }}
TEST_EMAIL_5: ${{ secrets.TEST_EMAIL_5 }}
TEST_PASSWORD_5: ${{ secrets.TEST_PASSWORD_5 }}
# api-smoke authenticates against Keycloak via ROPC. `dataspace` is a
# confidential client, so without this the token request returns 401
# and the job fails its preflight.
Expand All @@ -291,24 +308,41 @@ jobs:
with:
suite: functional
api_base_url: ${{ vars.DEV_API_BASE_URL }}
skip_provider: true
secrets:
HOME_URL_DEV: ${{ secrets.HOME_URL_DEV }}
TEST_EMAIL_1: ${{ secrets.TEST_EMAIL_1 }}
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
TEST_EMAIL_4: ${{ secrets.TEST_EMAIL_4 }}
TEST_PASSWORD_4: ${{ secrets.TEST_PASSWORD_4 }}
TEST_EMAIL_5: ${{ secrets.TEST_EMAIL_5 }}
TEST_PASSWORD_5: ${{ secrets.TEST_PASSWORD_5 }}
KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }}

tests-skipped:
name: Tests skipped (SKIP_DEV_TESTS)
needs: deploy
if: github.ref_name != 'main' && vars.SKIP_DEV_TESTS == 'true'
runs-on: ubuntu-latest
steps:
- run: |
echo "::notice::SKIP_DEV_TESTS=true: smoke and functional tests were skipped for this dev deploy."
echo "**SKIP_DEV_TESTS=true**: smoke and functional tests were skipped. Delete the repo variable to turn them back on." >> "$GITHUB_STEP_SUMMARY"

rollback-on-smoke-failure:
name: Rollback (smoke tests failed)
# `deploy` must be in needs: for needs.deploy.result to resolve here.
needs: [deploy, smoke-tests, functional-tests]
# Explicit results rather than failure(), so that a skipped functional stage
# on main never reads as a failure. !cancelled() keeps cancellation a no-op.
# Also the manual rollback button: Run workflow on dev with `rollback` ticked.
if: >-
${{ !cancelled() && needs.deploy.result == 'success' &&
(needs.smoke-tests.result == 'failure' || needs.functional-tests.result == 'failure') }}
${{ !cancelled() && ((inputs.rollback && github.ref_name != 'main') ||
(needs.deploy.result == 'success' &&
(needs.smoke-tests.result == 'failure' || needs.functional-tests.result == 'failure'))) }}
runs-on: ubuntu-latest
environment: ${{ github.ref_name == 'main' && 'production' || 'development' }}
# 50m: must comfortably exceed the Restore previous image step's own
Expand Down Expand Up @@ -347,6 +381,7 @@ jobs:
script: cd "$HOME/${{ env.DEPLOY_PATH }}" && sudo bash scripts/ci-rollback.sh "${{ vars.HEALTH_CHECK_URL || 'http://127.0.0.1:8000/health/' }}" "${{ github.actor }}"

- name: Mark this run as failed
if: ${{ !inputs.rollback }}
# The mitigation succeeded, but the run must still read RED -- a bad
# deploy that silently self-heals is a bad deploy nobody investigates.
run: |
Expand All @@ -357,10 +392,10 @@ jobs:
name: Finalize Deploy
needs: [deploy, smoke-tests, functional-tests]
# Explicit results, not success()/!failure(): on main the functional stage
# is skipped by design.
# is skipped by design, and on dev SKIP_DEV_TESTS skips smoke too.
if: >-
${{ !cancelled() && needs.deploy.result == 'success' &&
needs.smoke-tests.result == 'success' &&
(needs.smoke-tests.result == 'success' || needs.smoke-tests.result == 'skipped') &&
(needs.functional-tests.result == 'success' || needs.functional-tests.result == 'skipped') }}
runs-on: ubuntu-latest
environment: ${{ github.ref_name == 'main' && 'production' || 'development' }}
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/deploy-to-ecs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ jobs:
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
TEST_EMAIL_4: ${{ secrets.TEST_EMAIL_4 }}
TEST_PASSWORD_4: ${{ secrets.TEST_PASSWORD_4 }}
TEST_EMAIL_5: ${{ secrets.TEST_EMAIL_5 }}
TEST_PASSWORD_5: ${{ secrets.TEST_PASSWORD_5 }}
# api-smoke authenticates against Keycloak via ROPC. `dataspace` is a
# confidential client, so without this the token request returns 401
# and the job fails its preflight.
Expand Down
18 changes: 18 additions & 0 deletions .github/workflows/django-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,20 @@ jobs:
django-tests:
runs-on: ubuntu-latest

# The data database: tests marked data_db build real tables in it.
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10

steps:
- uses: actions/checkout@v4

Expand All @@ -40,6 +54,10 @@ jobs:
# tests/object_types/charts and the dataset metadata tests were left
# behind by the chart consolidation and fail on main: see #189.
- name: Run tests
env:
TEST_DATA_DB_URL: postgres://postgres:postgres@localhost:5432/postgres
# Fail the run instead of skipping the data_db tests if the database is missing.
REQUIRE_DATA_DB_TESTS: "1"
run: |
pytest tests/ \
--ignore=tests/object_types/charts \
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/pr-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,10 @@ jobs:
TEST_PASSWORD_1: ${{ secrets.TEST_PASSWORD_1 }}
TEST_EMAIL_2: ${{ secrets.TEST_EMAIL_2 }}
TEST_PASSWORD_2: ${{ secrets.TEST_PASSWORD_2 }}
TEST_EMAIL_3: ${{ secrets.TEST_EMAIL_3 }}
TEST_PASSWORD_3: ${{ secrets.TEST_PASSWORD_3 }}
TEST_EMAIL_4: ${{ secrets.TEST_EMAIL_4 }}
TEST_PASSWORD_4: ${{ secrets.TEST_PASSWORD_4 }}
TEST_EMAIL_5: ${{ secrets.TEST_EMAIL_5 }}
TEST_PASSWORD_5: ${{ secrets.TEST_PASSWORD_5 }}
KEYCLOAK_CLIENT_SECRET: ${{ secrets.KEYCLOAK_CLIENT_SECRET }}
3 changes: 2 additions & 1 deletion .github/workflows/sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,37 @@

jobs:
test:
runs-on: ubuntu-latest
# Pinned: ubuntu-latest (26.04) has no Python 3.9 build, which the SDK still supports.
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run type checking with mypy
run: |
mypy dataspace_sdk/ --ignore-missing-imports --config-file=/dev/null

- name: Run tests with pytest
run: |
pytest tests/test_auth.py tests/test_base.py tests/test_client.py tests/test_datasets.py tests/test_aimodels.py tests/test_usecases.py tests/test_exceptions.py -v -p no:django -o addopts= --override-ini=django_find_project=false --noconftest --cov=dataspace_sdk --cov-report=term-missing --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Loading
Loading