Skip to content

Implement Scripts - upload, list, get, delete #200

@bburda

Description

@bburda

Summary

Scripts are diagnostic programs that can be uploaded to the server and later executed on entities. This issue covers the script management endpoints (upload, list, read metadata, delete). Script execution is covered in a separate issue.


Proposed solution

1. POST /api/v1/{entity-path}/scripts

Upload a new diagnostic script to an entity.

Applies to entity types: Components, Apps

Path parameters:

Parameter Type Required Description
{entity-path} URL segment Yes e.g., components/engine_ecu or apps/temp_sensor

Request: Content-Type: multipart/form-data

The multipart body should contain:

  • file - the script binary/text content
  • metadata (optional) - JSON with script metadata:
{
  "name": "Sensor Calibration Check",
  "description": "Validates sensor calibration values against known thresholds",
  "parameters_schema": {
    "type": "object",
    "properties": {
      "threshold": { "type": "number", "default": 0.1 }
    }
  }
}

Response 201 Created:

{
  "id": "script_001",
  "name": "Sensor Calibration Check",
  "href": "/api/v1/apps/temp_sensor/scripts/script_001"
}

Error responses:

Status Error Code When
400 invalid-request Missing file part, invalid metadata
404 entity-not-found Entity doesn't exist
415 invalid-request Unsupported content type (not multipart/form-data)

2. GET /api/v1/{entity-path}/scripts

List all uploaded scripts for an entity.

Response 200 OK:

{
  "items": [
    {
      "id": "script_001",
      "name": "Sensor Calibration Check",
      "description": "Validates sensor calibration values",
      "href": "/api/v1/apps/temp_sensor/scripts/script_001"
    },
    {
      "id": "script_002",
      "name": "Network Diagnostics",
      "description": "Tests DDS communication paths",
      "href": "/api/v1/apps/temp_sensor/scripts/script_002"
    }
  ]
}

Each item is a ScriptDescription:

Field Type Required Description
id string Yes Script identifier
name string Yes Human-readable name
description string No Script description
href string Yes URI to this script resource
proximity_proof_required boolean No Whether execution requires proof of co-location
parameters_schema object No JSON Schema for script input parameters

3. GET /api/v1/{entity-path}/scripts/{script-id}

Read metadata for a specific script.

Path parameters:

Parameter Type Required Description
{script-id} string Yes Script identifier

Response 200 OK: Returns a single ScriptDescription (same fields as list items, potentially with more detail).

Error responses:

Status Error Code When
404 resource-not-found Script doesn't exist on this entity

4. DELETE /api/v1/{entity-path}/scripts/{script-id}

Delete an uploaded script. Cannot delete a script that is currently being executed.

Path parameters:

Parameter Type Required Description
{script-id} string Yes Script identifier

Response 204 No Content - script deleted.

Error responses:

Status Error Code When
404 resource-not-found Script doesn't exist
409 invalid-request Script is currently executing (has a running execution)

Additional context

Architecture

  • Create a ScriptManager class that stores uploaded scripts
  • Storage: temporary directory on the filesystem with metadata JSON sidecar files
  • Scripts do not survive server restart (unless using persistent storage)
  • The manager needs thread-safe access to the script registry

Security considerations

  • Script upload should require admin or operator role (integrate with auth middleware)
  • Store scripts in a controlled directory, not user-specified paths
  • Consider file size limits (configurable, e.g., 10MB max)

cpp-httplib multipart handling

The library has built-in multipart/form-data parsing - access files via req.files:

auto file_it = req.files.find("file");
if (file_it != req.files.end()) {
  const auto& file = file_it->second;
  // file.content, file.filename, file.content_type
}

Route registration

srv->Post((api_path("/components") + R"(/([^/]+)/scripts$)"), handler);
srv->Get((api_path("/components") + R"(/([^/]+)/scripts$)"), handler);
srv->Get((api_path("/components") + R"(/([^/]+)/scripts/([^/]+)$)"), handler);
srv->Delete((api_path("/components") + R"(/([^/]+)/scripts/([^/]+)$)"), handler);
// Same for /apps/

Tests

  • Unit test: upload script → 201
  • Unit test: list scripts → returns uploaded scripts
  • Unit test: get script metadata → correct data
  • Unit test: delete script → 204
  • Unit test: delete running script → 409
  • Unit test: get nonexistent script → 404

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions