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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- [#88](https://github.com/itk-dev/devops_itksites/pull/88)
- Let users use the API
- Add security to detection results API endpoint
- Add server and site collections API endpoints
- [#80](https://github.com/itk-dev/devops_itksites/pull/80) 5566: Service agreements
- Add security contract entity with crud controller
- Add Abstract full crud controller and extend on it in some cases
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ The system is build so that all analyzed data can be truncated safely and rebuil
by "replaying" the DetectionResults. This means that care must be taken when
manually maintained data and auto updated data must have cross references.

## API

Authenticated users can access a simple read-only API – see the API documentation on `/api/docs` for details.

### API keys

Run the `app:user:set-api-key` console command to set the API for a user:

``` shell
docker compose exec phpfpm php bin/console app:user:set-api-key <user-id>
```

Use the API key to make an authenticated request, e.g.

``` shell
curl --header 'accept: application/json' --header 'authorization: Apikey <the API key>' https://itksites.local.itkdev.dk/api/sites
```

## Development

```sh
Expand Down
7 changes: 5 additions & 2 deletions config/packages/api_platform.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
api_platform:
title: 'ITKsites Detection API'
description: 'REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.'
title: 'ITKsites API'
description: |
REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.

The API also provides read-only access to information on servers and sites created by processing detection results.
version: '1.0.0'

mapping:
Expand Down
9 changes: 7 additions & 2 deletions config/packages/security.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ security:
entity:
class: App\Entity\User
property: email

app_api_users:
chain:
providers: [app_server_provider, app_user_provider]

firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
Expand All @@ -20,7 +25,7 @@ security:
pattern: ^/api
custom_authenticators:
- App\Security\ApiKeyAuthenticator
provider: app_server_provider
provider: app_api_users

main:
custom_authenticators:
Expand All @@ -41,7 +46,7 @@ security:
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
- { path: ^/api, roles: ROLE_SERVER }
- { path: ^/api, roles: [ROLE_SERVER, ROLE_USER] }
- { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }

Expand Down
4 changes: 3 additions & 1 deletion fixtures/user.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
App\Entity\User:
user_admin:
__construct: ["admin@example.com", "Admin", [ROLE_ADMIN]]
__construct: ["Admin", "admin@example.com", [ROLE_ADMIN]]
user_user:
__construct: ["User", "user@example.com", [ROLE_USER]]
33 changes: 33 additions & 0 deletions migrations/Version20260702123347.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20260702123347 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD api_key VARCHAR(255) NOT NULL');
$this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D649C912ED9D ON user (api_key)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_8D93D649C912ED9D ON user');
$this->addSql('ALTER TABLE user DROP api_key');
}
}
187 changes: 185 additions & 2 deletions public/api-spec-v1.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"openapi": "3.1.0",
"info": {
"title": "ITKsites Detection API",
"description": "REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.",
"title": "ITKsites API",
"description": "REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.\n\nThe API also provides read-only access to information on servers and sites created by processing detection results.",
"version": "1.0.0"
},
"servers": [
Expand Down Expand Up @@ -92,6 +92,144 @@
"required": true
}
}
},
"/api/servers": {
"get": {
"operationId": "api_servers_get_collection",
"tags": [
"Server"
],
"responses": {
"200": {
"description": "Server collection",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Server-export"
}
}
},
"application/ld+json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Server-export"
}
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Retrieves the collection of Server resources.",
"description": "Retrieves the collection of Server resources.",
"parameters": [
{
"name": "page",
"in": "query",
"description": "The collection page number",
"required": false,
"deprecated": false,
"schema": {
"type": "integer",
"default": 1
},
"style": "form",
"explode": true
}
]
}
},
"/api/sites": {
"get": {
"operationId": "api_sites_get_collection",
"tags": [
"Site"
],
"responses": {
"200": {
"description": "Site collection",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Site-export"
}
}
},
"application/ld+json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Site-export"
}
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/ld+json": {
"schema": {
"$ref": "#/components/schemas/Error.jsonld"
}
},
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"links": {}
}
},
"summary": "Retrieves the collection of Site resources.",
"description": "Retrieves the collection of Site resources.",
"parameters": [
{
"name": "page",
"in": "query",
"description": "The collection page number",
"required": false,
"deprecated": false,
"schema": {
"type": "integer",
"default": 1
},
"style": "form",
"explode": true
}
]
}
}
},
"components": {
Expand Down Expand Up @@ -353,6 +491,43 @@
]
}
}
},
"Server-export": {
"type": "object",
"properties": {
"Name": {
"default": "",
"type": "string"
}
}
},
"Site-export": {
"type": "object",
"required": [
"PHP version"
],
"properties": {
"PHP version": {
"minLength": 1,
"maxLength": 10,
"default": "",
"type": "string"
},
"Primary domain": {
"readOnly": true,
"type": "string"
},
"Type": {
"default": "",
"type": "string"
},
"Server": {
"$ref": "#/components/schemas/Server-export"
},
"rootDir": {
"type": "string"
}
}
}
},
"responses": {},
Expand All @@ -378,6 +553,14 @@
{
"name": "DetectionResult",
"description": "Resource 'DetectionResult' operations."
},
{
"name": "Server",
"description": "Resource 'Server' operations."
},
{
"name": "Site",
"description": "Resource 'Site' operations."
}
],
"webhooks": {}
Expand Down
Loading
Loading