io7m | single-page | multi-page | epub | Cardant User Manual 1.0.0-beta0001

Cardant User Manual 1.0.0-beta0001

DATE 2023-12-16T17:05:50+00:00
DESCRIPTION User manual for the cardant server.
IDENTIFIER 9e6e25d5-7759-49a9-97b4-d0c645799e42
LANGUAGE en
SOURCE https://www.io7m.com/software/cardant/
TITLE Cardant User Manual 1.0.0-beta0001
The cardant package provides a server for managing inventories.

1.2. Features

  • Tracks user-defined items within user-defined hierarchical storage locations.
  • Strongly-typed metadata with user-defined types.
  • Rich search functionality; perform complex searches over item metadata with automatic pagination and sorting.
  • Full API access for all operations.
  • Full Java API for performing operations.
  • Fine-grained capability based security model for operations; Safely write external services that can perform operations while maintaining the principle of least privilege.
  • Command-line shell.
  • Complete audit log; every operation that changes the state of the system is logged in an append-only log.
  • Fully instrumented with OpenTelemetry.
  • A small, easily auditable codebase with a heavy use of modularity for correctness.
  • An extensive automated test suite with high coverage.
  • Platform independence. No platform-dependent code is included in any form, and installations can largely be carried between platforms without changes.
  • OSGi-ready
  • JPMS-ready
  • Support for Canonmill keystores.
  • ISC license.
The cardant server package is available from the following sources:
Regardless of the distribution method, the cardant package will contain a command named cardant that acts as the main entrypoint to all of the server and client functionality.
The cardant server requires a PostgreSQL server. The cardant server will create the required tables and database objects on first startup, given the name of a running PostgreSQL database, and a PostgreSQL role and password.
The cardant server delegates all user and password management to idstore and therefore requires a running idstore server in order to work.
A distribution package can be found at Maven Central.
The cardant command requires that a Java 21+ compatible JVM be accessible via /usr/bin/env java.
Verify the integrity of the distribution zip file:

2.4.4. Verify

$ gpg --verify com.io7m.cardant.main-1.0.0-beta0001-distribution.zip.asc
gpg: assuming signed data in 'com.io7m.cardant.main-1.0.0-beta0001-distribution.zip.asc'
gpg: Signature made Tue 28 Jun 2022 15:01:56 GMT
gpg:                using RSA key 3CCE59428B30462D10459909C5607DA146E128B8
gpg:                issuer "contact@io7m.com"
gpg: using pgp trust model
gpg: Good signature from "io7m.com (2022 maven-rsa-key) <contact@io7m.com>" [unknown]
Unzip the zip file, and set up the environment appropriately. The cardant command expects an environment variable named CARDANT_HOME to be defined that points to the installation directory.

2.4.6. Extract

$ unzip com.io7m.cardant.main-1.0.0-beta0001-distribution.zip
$ export CARDANT_HOME=$(realpath cardant)
$ ./cardant/bin/cardant
cardant: usage: cardant [command] [arguments ...]
...
OCI images are available from Quay.io for use with podman or docker.

2.5.1.2. Podman/Docker

$ podman pull quay.io/io7mcom/cardant:1.0.0-beta0001
$ podman run quay.io/io7mcom/cardant:1.0.0-beta0001
cardant: usage: cardant [command] [arguments ...]
...
The OCI image includes a cardant-healthcheck command that makes a request to a health endpoint on the Inventory API server. The command expects the server to be accessible on localhost inside the container, and requires that the CARDANT_HEALTHCHECK_PORT environment variable be set to the port used by the Admin API. By default, the container sets CARDANT_HEALTHCHECK_PORT to 30000 and therefore there is no need to set this variable manually if the server is configured with the default settings.
This feature may only be available when running the image under docker due to limitations in the OCI image specification. The functionality of the health check service can be used directly via the Inventory API.

2.5.2.3. Health Example

$ curl http://localhost:30000/health
OK
Given an appropriate configuration file in server.conf, it's necessary to tell cardant to configure the database and create an initial administrator. It's necessary to specify the idstore user ID of a user that will be considered to be the administrator of the cardant server:

2.6.1.2. Initialize

$ cardant initialize \
  --admin-id '92f83bce-3973-4db8-8aaf-d401443a9772' \
  --admin-name 'someone' \
  --configuration server.conf
It is not critical that the username given match the user ID on the idstore server; the name will be updated automatically from that server when a user logs in.
The server can now be run with cardant server:

2.6.2.2. Run

$ cardant server --configuration server.conf
info: [localhost/<unresolved>:30000] Inventory API server started
The server does not fork into the background and is designed to be run under process supervision.
Run cardant shell [1] to start the shell:

2.7.2. Shell

$ cardant shell
[cardant]# version
com.io7m.cardant 0.0.1-SNAPSHOT 20af71248a7784b0e5247eab4b1ebd28de284739
The cardant package uses PostgreSQL for all persistent data.
The cardant package sets up multiple roles during database initialization. The configured roles have different degrees of privileges in order to allow, for example, external systems such as database metrics collectors read-only access to the database. All the defined rules are declared with the built-in PostgreSQL restrictions such as nocreatedb, nocreaterole, etc.
During the startup of the cardant server, the server will connect to the database using the owner role and do any database table initialization and/or schema upgrades necessary. The server will then disconnect from the database, and then connect to the database again using the worker role. The worker role is then used for normal operation of the server; if this role is somehow compromised, the role only has a limited ability to do any damage to the database, and cannot affect the audit log at all.
The owner role is the role that owns the database and is permitted to create tables, create new roles, etc. This role is used by the cardant package when creating the database during the first run of the server, and for upgrading database schemas later. Administrators are free to pick the name of the role, although it is recommended that the role be named cardant_install to make it clear as to the purpose of the role.
If the PostgreSQL OCI image is used, it is common to have the image create this role automatically using the POSTGRES_USER and POSTGRES_PASSWORD variables:

2.8.2.2.3. Example

$ podman run \
  --name some-postgres \
  -e POSTGRES_USER=cardant_install \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -d postgres
The worker role is the role that is used for normal database operation. It is a role that has read/write access to all tables (except for the audit log which is restricted to being append-only), although it is not granted the ability to create new tables, drop tables, or do other schema manipulation. The role is always named cardant, and adminstrators are required to set a password for this role.
The reader role is a role that is permitted read-only access to some of the database. It is effectively an optional role that can be used by various database metrics systems if required. If a password is not specified for the role in the server's configuration file, then logging in is not permitted at all.

Footnotes

1
If running under podman or docker, remember to use the -i and -t options.
References to this footnote: 1
The cardant server is configured using a single XML-formatted configuration file. The format has a fully documented schema and so configuration files can be independently validated, and benefit from autocompletion in most modern IDEs.
The configuration file must consist of a single top-level Configuration element in the com.io7m.cardant:configuration:1 namespace. In modern IDEs, simply creating a file containing this element will immediately fill in all the other required child elements.
The smallest working configuration file, assuming a database at db.example.com and an idstore server at idstore.example.com:

3.2.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<Configuration xmlns="com.io7m.cardant:configuration:1"
               xmlns:ct="com.io7m.cardant:tls:1">

  <InventoryService ListenAddress="[::]"
                    ListenPort="30000"
                    SessionExpiration="PT30M"
                    ExternalAddress="http://cardant.example.com:30000">
    <ct:TLSDisabled/>
  </InventoryService>

  <Database Kind="POSTGRESQL"
            OwnerRoleName="cardant_install"
            OwnerRolePassword="892a2b68-2ddf-478a-a8ab-37172f6ac2fe"
            WorkerRolePassword="e61135dc-1d3f-4ab2-85ef-95ef49d66285"
            ReaderRolePassword="c2026069-97e7-45b1-85c4-a2349bbb847b"
            Address="db.example.com"
            Port="5432"
            Name="cardant"
            Create="true"
            Upgrade="true"
            Language="english"/>

  <Idstore BaseURI="https://idstore.example.com:50000"
           PasswordResetURI="https://idstore.example.com:50001/reset"/>

  <Limits MaximumFileUploadSizeOctets="10000000"
          MaximumCommandSizeOctets="10000000"/>

  <Maintenance TLSReloadInterval="PT24H"/>

  <OpenTelemetry LogicalServiceName="cardant01">
    <Logs Endpoint="http://logs.example.com:4317"
          Protocol="GRPC"/>
    <Metrics Endpoint="http://metrics.example.com:4317"
             Protocol="GRPC"/>
    <Traces Endpoint="http://traces.example.com:4317"
            Protocol="GRPC"/>
  </OpenTelemetry>

</Configuration>
The InventoryService section of the configuration file configures the main inventory service.
The ListenAddress and ListenPort attributes specify the address and port to which to the HTTP service will bind.
The ExternalAddress attribute specifies the external address that clients will use to connect to this server.
By convention, the inventory service should listen on TCP port 30000.
The InventoryService element must contain either a TLSEnabled or TLSDisabled element specifying whether TLS should be enabled or disabled, respectively. The TLSEnabled element describes the key store and trust store. The cardant server automatically reloads certificates periodically in order to work well in environments using the ACME protocol to issue certificates.
An example service configuration:

3.3.2.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<InventoryService xmlns="com.io7m.cardant:configuration:1"
                  xmlns:tls="com.io7m.cardant:tls:1"
                  ListenAddress="[::]"
                  ListenPort="30000"
                  SessionExpiration="PT30M"
                  ExternalAddress="http://cardant.example.com:30000">
  <tls:TLSEnabled>
    <tls:KeyStore Type="CANONMILL"
                  Provider="CANONMILL"
                  Password="ignored"
                  File="/cardant/keystore.xml"/>
    <tls:TrustStore Type="JKS"
                    Provider="SUN"
                    Password="changeit"
                    File="/usr/lib/jvm/java-21-openjdk/lib/security/cacerts"/>
  </tls:TLSEnabled>
</InventoryService>
The Idstore section of the configuration file configures the external idstore server.
The BaseURI attribute specifies the base URI of the User API of the external idstore server. This server is used to authenticate users whenever they try to log in to the cardant server.
The PasswordResetURI attribute specifies the URI to which users should be redirected if they want to reset their passwords. This is the URI of the User View service on the external idstore server.
An example service configuration:

3.4.3.2. Example

<?xml version="1.0" encoding="UTF-8" ?>

<Idstore xmlns="com.io7m.cardant:configuration:1"
         BaseURI="https://idstore.example.com:50000"
         PasswordResetURI="https://idstore.example.com:50001/reset"/>
The Maintenance section of the configuration file configures the maintenance service.
The TLSReloadInterval attribute specifies how frequently the server will reload the TLS certificates for the HTTP services; the server will reload certificates every time this interval elapses. The attribute must be formatted as an ISO 8601 duration string.
An example maintenance configuration:

3.5.3.2. Example

<Maintenance TLSReloadInterval="PT30M"/>
The Limits section of the configuration file configures various limits for the server.
The MaximumFileUploadSizeOctets attribute specifies the maximum size allowed for files uploaded the server. Requests to upload files larger than this limit will be rejected.
The MaximumCommandSizeOctets attribute specifies the maximum size allowed for commands sent to the server. Commands larger than this limit will be rejected.
An example configuration:

3.6.4.2. Example

<Limits MaximumFileUploadSizeOctets="10000000"
        MaximumCommandSizeOctets="10000000"/>
The Database section of the configuration file configures the database.
The OwnerRoleName attribute specifies the name of the role that owns the database. Conventionally, this should be cardant_install, but can be set independently by the database administrator.
The OwnerRolePassword attribute specifies the password of the owner role.
The WorkerRolePassword attribute specifies the password of the worker role used for normal database operation.
The ReaderRolePassword attribute specifies the password of the reader role used for read-only database access. If this attribute is not specified, logging in using this role will be prevented.
The MinimumPoolConnections attribute specifies the number of database connections to keep idle in the internal database connection pool. If this attribute is not specified, the default is 0.
The MaximumPoolConnections attribute specifies the maximum number of database connections to allow in the internal database connection pool. If this attribute is not specified, the default is 10. If the number of connections in the internal database pool reaches this value, the application will be forced to wait for a connection to become idle before it can obtain a new connection.
The Name attribute specifies the database name.
The Create attribute specifies that the database schema should be created on startup.
The Upgrade attribute specifies that the database schema should be upgraded on startup.
The Language attribute specifies the language that will be used internally for full-text searching.
An example database configuration:

3.7.2.2. Example

<Database Kind="POSTGRESQL"
          OwnerRoleName="cardant_install"
          OwnerRolePassword="mydatabase"
          WorkerRolePassword="willquickly"
          ReaderRolePassword="becompromised"
          Address="db.example.com"
          Port="5432"
          Name="cardant"
          Create="true"
          Upgrade="true"
          Language="english"
          MinimumPoolConnections="1"
          MaximumPoolConnections="5"/>
The OpenTelemetry section of the configuration file configures Open Telemetry. This section is optional and telemetry is disabled if the section is not present.
The logical service name should be provided in the LogicalServiceName attribute.
If the OpenTelemetry element contains a Traces element, OTLP traces will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
If the OpenTelemetry element contains a Metrics element, OTLP metrics will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
If the OpenTelemetry element contains a Logs element, OTLP logs will be sent to a specified endpoint. The Endpoint attribute specifies the endpoint, and the Protocol attribute can either be GRPC or HTTP.
An example Open Telemetry configuration:

3.8.5.2. Example

<OpenTelemetry LogicalServiceName="idstore">
  <Logs Endpoint="http://logs.example.com:4317"
        Protocol="GRPC"/>
  <Metrics Endpoint="http://metrics.example.com:4317"
           Protocol="GRPC"/>
  <Traces Endpoint="http://traces.example.com:4317"
          Protocol="GRPC"/>
</OpenTelemetry>
The XSD schema for the configuration file is as follows:

3.9.2. Configuration Schema

<?xml version="1.0" encoding="UTF-8" ?>

<!--
  Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->

<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="com.io7m.cardant:configuration:1"
        xmlns:ct="com.io7m.cardant:tls:1"
        xmlns:c="com.io7m.cardant:configuration:1">

  <import namespace="com.io7m.cardant:tls:1"/>

  <annotation>
    <documentation>
      The schema for server configuration files.
    </documentation>
  </annotation>

  <simpleType name="DatabaseKind">
    <annotation>
      <documentation>
        The kind of the target database. Currently, only PostgreSQL is supported.
      </documentation>
    </annotation>

    <restriction base="string">
      <enumeration value="POSTGRESQL">
        <annotation>
          <documentation>
            The database is PostgreSQL.
          </documentation>
        </annotation>
      </enumeration>
    </restriction>
  </simpleType>

  <element name="Idstore">
    <annotation>
      <documentation>
        Configuration for the idstore server that will be used for user identity information.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="BaseURI"
                 type="anyURI"
                 use="required">
        <annotation>
          <documentation>
            The base URI of the idstore user API.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="PasswordResetURI"
                 type="anyURI"
                 use="required">
        <annotation>
          <documentation>
            The password reset URI to which to redirect users who want to reset their password.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <simpleType name="OpenTelemetryProtocol">
    <annotation>
      <documentation>
        The protocol used to deliver OpenTelemetry data.
      </documentation>
    </annotation>

    <restriction base="string">
      <enumeration value="GRPC">
        <annotation>
          <documentation>
            The data will be sent using gRPC.
          </documentation>
        </annotation>
      </enumeration>
      <enumeration value="HTTP">
        <annotation>
          <documentation>
            The data will be sent using HTTP(s).
          </documentation>
        </annotation>
      </enumeration>
    </restriction>
  </simpleType>

  <element name="Logs">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry logs.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP log data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send log data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Metrics">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry metrics.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP metrics data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send metrics data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Traces">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry traces.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Endpoint"
                 use="required"
                 type="anyURI">
        <annotation>
          <documentation>
            The endpoint to which OTLP trace data will be sent.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Protocol"
                 use="required"
                 type="c:OpenTelemetryProtocol">
        <annotation>
          <documentation>
            The protocol used to send trace data.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="OpenTelemetry">
    <annotation>
      <documentation>
        Configuration information for OpenTelemetry.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="c:Logs"
                 minOccurs="0"
                 maxOccurs="1"/>
        <element ref="c:Metrics"
                 minOccurs="0"
                 maxOccurs="1"/>
        <element ref="c:Traces"
                 minOccurs="0"
                 maxOccurs="1"/>
      </sequence>

      <attribute name="LogicalServiceName"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The logical name of the service as it will appear in OpenTelemetry.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Database">
    <annotation>
      <documentation>
        Configuration information for the database.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="Kind"
                 type="c:DatabaseKind"
                 use="required"/>

      <attribute name="OwnerRoleName"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The name of the role that owns the database. This is used for the initial database setup, and for upgrades.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="OwnerRolePassword"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The password of the role that owns the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="WorkerRolePassword"
                 use="required"
                 type="string">
        <annotation>
          <documentation>
            The password of the role used for normal database operation. This is an unprivileged role that does not have
            the ability to perform DDL or other database-changing operations.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="ReaderRolePassword"
                 use="optional"
                 type="string">
        <annotation>
          <documentation>
            The password of the role used for read-only database operation. If this attribute is not specified, the
            read-only role is not allowed to log in.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Address"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The address of the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Port"
                 type="integer"
                 use="required">
        <annotation>
          <documentation>
            The port used to connect to the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Name"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The name of the database.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Create"
                 type="boolean"
                 use="required">
        <annotation>
          <documentation>
            If set to true, the database and tables will be created if they do not already exist.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Upgrade"
                 type="boolean"
                 use="required">
        <annotation>
          <documentation>
            If set to true, the database and tables will be upgraded to the latest supported schema version.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="Language"
                 type="string"
                 use="required">
        <annotation>
          <documentation>
            The language used for database search indexes (such as 'english'). See
            https://www.postgresql.org/docs/current/locale.html.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MinimumPoolConnections"
                 use="optional"
                 default="1"
                 type="unsignedInt">
        <annotation>
          <documentation>
            The minimum number of connections to keep idle in the database connection pool.
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MaximumPoolConnections"
                 use="optional"
                 default="10"
                 type="unsignedInt">
        <annotation>
          <documentation>
            The maximum number of connections to allow in the database connection pool. When this number of
            connections is active in the pool, the application will be forced to wait until a connection
            becomes idle upon requesting another connection.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <complexType name="HTTPService">
    <sequence minOccurs="1"
              maxOccurs="1">
      <group ref="ct:TLSGroup"/>
    </sequence>

    <attribute name="ListenAddress"
               type="string"
               use="required">
      <annotation>
        <documentation>
          The address upon which this HTTP service will listen.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="ListenPort"
               type="integer"
               use="required">
      <annotation>
        <documentation>
          The port upon which this HTTP service will listen.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="ExternalAddress"
               type="anyURI"
               use="required">
      <annotation>
        <documentation>
          The address by which this service is accessible to the outside world. The service will typically be configured
          behind a reverse proxy to provide TLS.
        </documentation>
      </annotation>
    </attribute>

    <attribute name="SessionExpiration"
               type="duration"
               use="optional">
      <annotation>
        <documentation>
          The expiration time for sessions.
        </documentation>
      </annotation>
    </attribute>
  </complexType>

  <element name="InventoryService"
           type="c:HTTPService">
    <annotation>
      <documentation>
        Configuration for the Inventory API service.
      </documentation>
    </annotation>
  </element>

  <element name="Limits">
    <annotation>
      <documentation>
        Configuration for various limits.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="MaximumFileUploadSizeOctets"
                 type="unsignedLong"
                 use="required">
        <annotation>
          <documentation>
            The maximum permitted size of uploaded files (in octets).
          </documentation>
        </annotation>
      </attribute>

      <attribute name="MaximumCommandSizeOctets"
                 type="unsignedLong"
                 use="required">
        <annotation>
          <documentation>
            The maximum permitted size of ordinary commands (in octets).
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Maintenance">
    <annotation>
      <documentation>
        Configuration for the server's periodic maintenance tasks.
      </documentation>
    </annotation>

    <complexType>
      <attribute name="TLSReloadInterval"
                     type="duration"
                     use="optional">
        <annotation>
          <documentation>
            The interval at which TLS contexts will be reloaded. If not
            specified, TLS contexts will not be reloaded.
          </documentation>
        </annotation>
      </attribute>
    </complexType>
  </element>

  <element name="Configuration">
    <annotation>
      <documentation>
        The top-level configuration element.
      </documentation>
    </annotation>

    <complexType>
      <sequence>
        <element ref="c:InventoryService"/>
        <element ref="c:Database"/>
        <element ref="c:Idstore"/>
        <element ref="c:Limits"/>
        <element ref="c:Maintenance"/>
        <element ref="c:OpenTelemetry"
                 minOccurs="0"
                 maxOccurs="1"/>
      </sequence>
    </complexType>
  </element>

</schema>

3.9.3. TLS Schema

<?xml version="1.0" encoding="UTF-8" ?>

<!--
  Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
  IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-->

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="com.io7m.cardant:tls:1"
            xmlns:nt="com.io7m.cardant:tls:1">

  <xsd:complexType name="StoreType"
                   abstract="true">
    <xsd:attribute name="Type"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="Provider"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="Password"
                   type="xsd:string"
                   use="required"/>
    <xsd:attribute name="File"
                   type="xsd:string"
                   use="required"/>
  </xsd:complexType>

  <xsd:complexType name="KeyStoreType">
    <xsd:complexContent>
      <xsd:extension base="nt:StoreType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:complexType name="TrustStoreType">
    <xsd:complexContent>
      <xsd:extension base="nt:StoreType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="KeyStore"
               type="nt:KeyStoreType"/>

  <xsd:element name="TrustStore"
               type="nt:TrustStoreType"/>

  <xsd:complexType name="TLSType"
                   abstract="true"/>

  <xsd:complexType name="TLSDisabledType">
    <xsd:complexContent>
      <xsd:extension base="nt:TLSType"/>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TLSDisabled"
               type="nt:TLSDisabledType"/>

  <xsd:complexType name="TLSEnabledType">
    <xsd:complexContent>
      <xsd:extension base="nt:TLSType">
        <xsd:sequence>
          <xsd:element ref="nt:KeyStore"/>
          <xsd:element ref="nt:TrustStore"/>
        </xsd:sequence>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TLSEnabled"
               type="nt:TLSEnabledType"/>

  <xsd:group name="TLSGroup">
    <xsd:choice>
      <xsd:element ref="nt:TLSDisabled"/>
      <xsd:element ref="nt:TLSEnabled"/>
    </xsd:choice>
  </xsd:group>

</xsd:schema>
The cardant package provides a server-based application to track inventory. It stores detailed information about types of items, and can store the counts of those items present in defined locations.
This section of the documentation describes the internal cardant model.
An item is an object that is tracked by the inventory system. When the cardant package refers to items, it should more accurately be understood to be referring to classes of items. That is, the inventory system tracks sets of items of a given class within locations. An item has associated metadata, an identifier that uniquely identifies the item class, zero or more types that can constrain the metadata associated with the item, and a name.
Metadata is data associated with an item that describes that item. Items can have any number of metadata values, and inventory managers can introduce strong requirements on the presence and types of metadata on items through the application of types.
A type is a label that can be applied to an item that will constrain the metadata associated with that item. A type on an item refers to a type declaration created by the inventory manager. A type declaration is essentially a record type in the sense that it defines a set of named metadata values along with their individual scalar types.
Types are intended to ensure the integrity and quality of metadata associated with items, and allow for more precise searching. For example, inventory managers might define a voltage_regulator type that is applied to electronics components within the inventory that are voltage regulators. The voltage_regulator type might be declared to require that metadata includes numeric values input_voltage and output_voltage that describe the input and output voltages of the regulator. Any attempt to update an item that has the voltage_regulator type applied without providing values for the input_voltage and output_voltage metadata will be rejected with a clear error message.
As mentioned, types are intended to facilitate more precise searching. It is possible to, for example, search for all items in the inventory that have an output_voltage metadata value, but this does not imply that all the returned items will be voltage regulators. With a well-designed and well-managed inventory, one can simply search for all items that have the type voltage_regulator (and then perhaps narrow down the search by asking for only those items that have an output_voltage value equal to 5.0).
A scalar type is a named type derived from one of the following base types:

4.2.4.2. Metadata Value Types

Name Description
Integral A type used to express integer values.
Real A type used to express real/fractional values.
Monetary A type used to express monetary values. All values include an associated currency unit.
Time A type used to express timestamp values. All values include a time zone value.
Text A type used to express plain string values.
Typically, a named scalar type will augment an existing scalar base type with further constraints such as a bound on the range of allowed values. For example, an inventory manager supervising a stock of computer keyboards might define a keyboard type with a keys field of a scalar type keyboard.keys. The keyboard.keys scalar type might be derived from the Integral scalar type with a bound of [68, 104], expressing that keyboard may have as few as 68 or as many as 104 keys.
Items can have zero or more attachments. An attachment is simply a file associated with the item according to a given relation. For example, an electronics component might have a PDF datasheet associated with it using a datasheet relation. Relations are entirely user-defined, and it is the responsibility of the inventory manager to use sensible and consistent relations.
A stock instance is an object that associates items with locations. A stock instance effectively says "this item is present in this location". A stock instance may be a set instance or a serial instance.
Stock instances have globally-unique UUID identifier values.
A set instance is a stock instance that describes a set of items that, by themselves, do not have any kind of unique identities.
For example, an inventory manager that is managing an inventory that contains rolls of passive electronics components such as resistors would use set instances to describe sets of resistors in the inventory. The resistors themselves do not have serial numbers or any kind of individual identity and therefore there is no reason to (or, in fact, any way to) track the individual resistors; only the count of resistors has any meaning.
A set instance always has a count ≥ 0. Attempting to remove items from a set instance such that the count would become negative is an error.
A serial instance is a stock instance that describes a single item that may have one or more identities associated with it.
For example, an inventory manager that is managing an inventory that contains musical instruments would use serial instances to identify individual instruments in the inventory. Instruments of each type are distinguished from other instruments of the same type by way of serial numbers. A serial number in the cardant package is an arbitrary string. Serial numbers are unique for a given item class but are not assumed be globally unique. After all, two manufacturers of completely different products might coincidentally manage to use the same serial numbers for their products. Within a single manufacturer's product range, however, serial numbers will most assuredly be unique.
As mentioned, stock instances do have a guaranteed-unique identifier, so this can be used as a system-enforced unique identifier for an item if required.
Stock is added to and removed from locations by repositing. Intuitively, a reposit operation atomically adds zero or more instances of an item to a location, and removes zero or more items from another location in a single step. A reposit operation is either a set reposit or a serial reposit.
A set reposit is an operation used to move sets of items that do not, themselves, have useful individual identities.
A serial reposit is an operation used to move items that have individual identities.
Reposit operations are described by the following algebraic datatype:

4.3.4.4.2. Reposit

type StockReposit =
  | CAStockRepositRemove CAStockInstanceID
  | CAStockRepositSerialIntroduce CAStockInstanceID CAItemID CALocationID CAItemSerial
  | CAStockRepositSerialMove CAStockInstanceID CALocationID
  | CAStockRepositSerialNumberAdd CAStockInstanceID CAItemSerial
  | CAStockRepositSerialNumberRemove CAStockInstanceID CAItemSerial
  | CAStockRepositSetAdd CAStockInstanceID Long
  | CAStockRepositSetIntroduce CAStockInstanceID CAItemID CALocationID Long
  | CAStockRepositSetMove CAStockInstanceID CAStockInstanceID CALocationID Long
  | CAStockRepositSetRemove CAStockInstanceID Long
A reposit (CAStockRepositSerialIntroduce i t l s) introduces a new serial stock instance i of item t, placing it in location l, and using the initial serial number s.
A reposit (CAStockRepositRemove i) removes the stock instance i.
A reposit (CAStockRepositSerialMove i l) moves an existing serial stock instance i from the location it is currently in to the new location l.
A reposit (CAStockRepositSerialNumberAdd i s) adds a new serial number s to an existing serial stock instance i.
A reposit (CAStockRepositSerialNumberRemove i s) removes a serial number s from an existing serial stock instance i.
A reposit (CAStockRepositSetIntroduce i t l c) introduces a new set stock instance i of item t, placing it in location l, and using the initial count c.
A reposit (CAStockRepositSetAdd i c) adds c items to an existing set stock instance i.
A reposit (CAStockRepositSetMove i0 i1 l c) moves c items from an existing set stock instance i0 to the set stock instance i1.
A reposit (CAStockRepositSetRemove i c) removes c items from an existing set stock instance i.
A location is an object that tracks item counts. Locations, as a concept, are kept deliberately abstract to allow for a wide range of use-cases. A location might represent a physical storage bin in a warehouse, or it might represent a deployed computer system that has been built using items taken from the inventory. By treating locations as generic containers in this manner, the system is intended to allow for supporting different use cases such as managing retail inventory, or managing the deployment of computer parts in a laboratory. Locations are hierarchical.
Locations carry metadata in the same manner as items.
Locations can have applied types in the same manner as items.
Locations can have attachments in the same manner as items.
Locations form a hierarchy (specifically, a tree) in that any location may have any number of child locations, although a location may only have at most one parent. Locations can be reparented at any time; they are not locked into having whichever parent they had when they were created.
The hierarchical nature of locations can be used to model different kinds of inventory arrangements. For example, a manager of computer laboratories might define Laboratory A and Laboratory B locations. Within those locations, the manager might define locations Computer A1, Computer A2, Computer A3, and so on. Within the Computer A1 location, the manager might place a single motherboard item, one or more CPU items, and so on, from the inventory. This allows the manager to know what computer parts they have, and the computers in which those parts are being used in the laboratories under their supervision. Additionally, should one assembled computer be moved from one laboratory to another, the manager can simply reparent the computer location to the new laboratory.
Conversely, a manager of a retail business might define a Storage Room A location, and then within that location, define Shelf A01, Shelf A02, Shelf A03, etc. The manager can then place items onto those storage shelf locations. This allows the manager to track what stock they have, and exactly where they're keeping each kind of item.
Types are introduced into a running cardant server using type packages. A type package is simply a named, versioned container of types that can be uploaded and installed into the server's database atomically.
Type packages are identified by their name and version. It is not permitted to have two packages with the same name but different versions installed at the same time. A type package name is a Lanark dotted name (such as com.io7m.example) and the types declared within the package have their names derived by concatenating their unqualified names onto the end of the package name. So, for example, a package com.io7m.example that contains a scalar type named t will cause the scalar type com.io7m.example:t to be created on the server when the package is installed.
A type package may import other type packages. An import consists of a package name and a version range. When a user tries to install a type package p, each import i declared by p is examined, and the server inspects its own set of installed packages and verifies that a package is installed with both a name that matches i and a version that falls within the range declared by i. If no such package exists, the type package installation is rejected and the system is left untouched.
For the sake of simplicity, and because the number of installed type packages is expected to be small and not change particularly often, imports are merely an install-time check. It is possible (but heavily discouraged) for type packages to refer to types in packages that they have not imported.
Type packages are serialized using the given XML schema.
The cardant package uses role-based access control for all operations.
Each user has a set of roles associated with it. When the user attempts to perform an operation on the server, the account's roles are checked to see if it has permission to perform the action.
A role R may be granted to a user A by user B if B has role R. Accordingly, a role R may be revoked from a user A by user B if B has role R.
A user holding the inventory.admin role effectively always has all available roles. If new roles are added in future versions of the cardant package, users holding the inventory.admin role will be automatically granted the new roles. It is recommended to limit this role to a single user, and to avoid using that user account for day-to-day operations.
The following roles are available:

4.6.3.2. Roles

Name Description
inventory.files.writer A writer of inventory files.
inventory.files.reader A reader of inventory files.
inventory.items.writer A writer of inventory items.
inventory.items.reader A reader of inventory items.
inventory.locations.writer A writer of inventory locations.
inventory.locations.reader A reader of inventory locations.
audit.reader A reader of the audit log.
inventory.admin An all-powerful administrator of inventories.
The server maintains an append-only audit log consisting of a series of audit events. An audit event has an integer id, an owner (represented by an account UUID), a timestamp, a type, and a message consisting of a set of key/value pairs.
Each operation that changes the underlying database typically results in an event being logged to the audit log.
The inventory API is the interface exposed to user clients. It exposes a Cedarbridge-based API over HTTP, using the included schema.
The inventory API is the primary means by which clients perform operations on the server.
The cardant package is extensively instrumented with OpenTelemetry in order to allow for the server to be continually monitored. The package publishes metrics, logs, and traces, all of which can be independently enabled or disabled. Most installations will only want to enable metrics or logs in production; traces are more useful when trying to diagnose performance problems, or for doing actual development on the cardant package.
The package publishes the following metrics that can be used for monitoring:

5.2.1.2. Metrics

Name Description
cardant_up A gauge that displays a constant 1 value while the server is up.
cardant_http_time A gauge that logs the time each HTTP request has taken in nanoseconds.
cardant_http_requests A counter that is incremented every time an HTTP request is handled.
cardant_http_requests_size A counter that is incremented with the size of every HTTP request.
cardant_http_responses_size A counter that is incremented with the size of every produced HTTP response.
cardant_http_responses_2xx A counter that is incremented with every HTTP response that produces a 2xx status code.
cardant_http_responses_4xx A counter that is incremented with every HTTP response that produces a 4xx status code. A 4xx status code should be understood to mean "blame the client".
cardant_http_responses_5xx A counter that is incremented with every HTTP response that produces a 5xx status code. A 5xx status code should be understood to mean "blame the server".
cardant_sessions A gauge that displays the number of currently active user sessions.
The package may produce other metrics, however these are undocumented and should not be relied upon.
The cardant package provides a command-line interface for performing tasks such as starting the server, checking configuration files, and etc. The base cardant command is broken into a number of subcommands which are documented over the following sections.

6.1.2. Command-Line Overview

cardant: usage: cardant [command] [arguments ...]

  The cardant server command-line application.

  Use the "help" command to examine specific commands:

    $ cardant help help.

  Command-line arguments can be placed one per line into a file, and
  the file can be referenced using the @ symbol:

    $ echo help > file.txt
    $ echo help >> file.txt
    $ cardant @file.txt

  Commands:
    help          Show usage information for a command.
    initialize    Initialize the server and database.
    server        Start the server.
    shell         Start the shell.
    version       Show the application version.

  Documentation:
    https://www.io7m.com/software/cardant/
All subcommands accept a --verbose parameter that may be set to one of trace, debug, info, warn, or error. This parameter sets the lower bound for the severity of messages that will be logged. For example, at debug verbosity, only messages of severity debug and above will be logged. Setting the verbosity to trace level effectively causes everything to be logged, and will produce large volumes of debugging output.
The cardant command-line tool uses quarrel to parse command-line arguments, and therefore supports placing command-line arguments into a file, one argument per line, and then referencing that file with @. For example:

6.1.5. @ Syntax

$ cardant server --configuration server.conf

$ (cat <<EOF
--configuration
server.conf
EOF
) > args.txt

$ cardant @args.txt
All subcommands, unless otherwise specified, yield an exit code of 0 on success, and a non-zero exit code on failure.
initialize - Initialize the server
The initialize command initializes or updates the database and the initial administrator.

6.2.3.1. --admin-id

Attribute Value
Name --admin-id
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The ID of the user that will be the initial administrator.

6.2.3.2. --admin-name

Attribute Value
Name --admin-name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the user that will be the initial administrator.

6.2.3.3. --configuration

Attribute Value
Name --configuration
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The configuration file.

6.2.3.4. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.2.4.1. Example

$ cardant initialize \
  --admin-id '92f83bce-3973-4db8-8aaf-d401443a9772' \
  --admin-name 'someone' \
  --configuration server.conf
package get - Get the text of a package
The package get command gets the text of a built-in type package. The text of the package can be written to a file and then optionally installed with type-package-install shell command.

6.3.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The package name.

6.3.3.2. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

6.3.3.3. --version

Attribute Value
Name --version
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The package version.

6.3.4.1. Example

$ cardant package get --name cardant.product --version 1.0.0
<?xml version="1.0" encoding="UTF-8" ?>
<Package xmlns="com.io7m.cardant:type_packages:1">
  <PackageInfo Name="cardant.product"
               Version="1.0.0"
               Description="Manufactured products."/>
  <TypeScalarText Name="manufacturer"
...

$ cardant package get --name cardant.product --version 1.0.0 --output out.xml
package list - List packages that are available for install
The package list command lists the built-in type packages that are available to install.
The command has no parameters.

6.4.4.1. Example

$ cardant package list
# Package         Version
cardant.product   1.0.0-SNAPSHOT
server - Start the server
The server command starts the server.

6.5.3.1. --configuration

Attribute Value
Name --configuration
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The configuration file.

6.5.3.2. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.5.4.1. Example

$ cardant server --configuration server.conf
info: [localhost/<unresolved>:30000] Inventory API server started
shell - Start the shell
The server command starts the shell.

6.6.3.1. --verbose

Attribute Value
Name --verbose
Type com.io7m.quarrel.ext.logback.QLogLevel
Default Value info
Cardinality [1, 1]
Description Set the logging level of the application.

6.6.4.1. Example

$ cardant shell
[cardant]# version
com.io7m.cardant 0.0.1-SNAPSHOT 20af71248a7784b0e5247eab4b1ebd28de284739
version - Display the package version
The version command displays the current version of the package.
The command has no parameters.

6.7.4.1. Example

cardant: usage: version

  Show the application version.

  The command does not accept any named arguments.

  The command does not accept any positional arguments.
  
  The version command produces the following output, in order:
  
    * The application ID (such as "com.io7m.quarrel")
    * The application version (such as "1.2.0")
    * The application build (such as "eacd59a2")
  
  For example, for a hypothetical application named "quarrel":
  
    $ quarrel version
    com.io7m.quarrel 1.2.0 eacd59a2
In addition to the API access the server provides, the cardant package includes an interactive command-line shell for performing tasks.
The shell is started using the shell command. The shell supports basic tab-completion and history accessed with the up and down arrows.
When running on an appropriate terminal, the shell supports tab completion for command and most command arguments. Begin typing the name of a command, or the name of a command argument, and then press tab. A set of completion options will be displayed.
When running on an appropriate terminal, the command shell stores the history of commands in memory (the history is not saved to disk, for security reasons). Press the up and down arrows to navigate to previously executed commands.
Arguments to shell commands may be quoted using the " or ' characters. This is required when calling commands that take arguments that may need to contain strings.
Typically, the ENTER key ends the current line. This will cause the shell to interpret the contents of a line as a command and execute it. Pressing ALT+ENTER inserts an actual newline character without executing the command. This can be useful if an argument to a command needs to contain a newline character:
When in this mode, the cursor can be moved around freely with the arrow keys to allow for editing lines. Pressing the ENTER key ends the multiline editing mode and executes the command.
The shell provides different formatting options for tabular data.

7.1.6.2. Formatters

Name Description
PRETTY Provides pretty Unicode tables.
RAW Provides raw tables.
The formatter can be set using the set command.

7.1.6.4. Example

[cardant]$ set --formatter PRETTY
[cardant]$ audit-search-begin
Search results: Page 1 of 1
┌────┬──────────────────────────────────────┬────────────────┬─────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐
│ ID │ Owner                                │ Type           │ Time                        │ Data                                                                    │
├────┼──────────────────────────────────────┼────────────────┼─────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤
│ 1  │ c5574d46-7413-43c8-b6db-31001c382ca3 │ USER_LOGGED_IN │ 2023-12-21T11:30:11.171839Z │ {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236} │
└────┴──────────────────────────────────────┴────────────────┴─────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘

[cardant]$ set --formatter RAW
[cardant]$ audit-search-begin
# Search results: Page 1 of 1
#--------------------------------
1 c5574d46-7413-43c8-b6db-31001c382ca3 USER_LOGGED_IN 2023-12-21T11:30:11.171839Z {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236}
The shell allows for setting server bookmarks. A server bookmark is essentially the information required to log in to a particular server as a particular user.
Bookmarks can be created with the bookmark-put command, listed with the bookmark-list command, and used with the bookmark-login command.

7.1.7.3. Example

[cardant]$ bookmark-put --user example --password F7B7D37C620C70BF03353148582AC97D --hostname 10.1.6.1 --name local0

[cardant]$ bookmark-list
┌─────────────────┬─────────────────────────┬───────┬───────┬──────────────────┐
│ Name            │ Host                    │ Port  │ TLS   │ User             │
├─────────────────┼─────────────────────────┼───────┼───────┼──────────────────┤
│ local0          │ 10.1.6.1                │ 30000 │ false │ example          │
└─────────────────┴─────────────────────────┴───────┴───────┴──────────────────┘
[cardant]$ bookmark-login --name local0

[cardant]$ self
User ID: c5574d46-7413-43c8-b6db-31001c382ca3
┌────────────────────────────────────────────────────────────────────────────────┐
│ Role                                                                           │
├────────────────────────────────────────────────────────────────────────────────┤
│ audit.reader                                                                   │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.admin                                                                │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.reader                                                     │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.writer                                                     │
└────────────────────────────────────────────────────────────────────────────────┘
The cardant package exposes many commands for searching the database.
All search commands in the cardant package provide automatic pagination. Searches are performed by beginning a search with a begin command which will yield the first page of results. Searches are then continued with next and previous commands which will return the next and previous pages of results, respectively. It is an error to try to execute a next or previous command without first having executed a begin command.
Each page of search results includes the number of the current page, and the number of pages of search results available. Attempting to seek beyond the end of the set of pages with a next command is not an error; the server will simply repeatedly return the last page in the set. Similarly, attempting to seek before the first page of results with a previous command will simply return the first page of results, repeatedly.
The search commands typically accept different filtering expressions to allow for very rich search capabilities. The syntactic forms of all the different expression types are listed in the following sections of the documentation, and can also be inspected using the syntax-list and syntax-show shell commands.
A name match expression is an expression used to filter search results. The expression is evaluated using the object's name as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.2.3. Forms

  • with-any-name
  • (with-name-equal-to n)
  • (with-name-not-equal-to n)
  • (with-name-similar-to n)
  • (with-name-not-similar-to n)
Expressions have the following semantics, given in terms of a match_name_evaluate function:

7.1.8.2.5. Semantics

match_name_evaluate with-any-name n                 ⇒ true
match_name_evaluate (with-name-equal-to m) n        ⇒ n = m
match_name_evaluate (with-name-not-equal-to m) n    ⇒ n ≠ m
match_name_evaluate (with-name-similar-to m) n      ⇒ n ≃ m
match_name_evaluate (with-name-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.2.6. Semantics Explanation

  • An expression with-any-name always evaluates to true.
  • For all names m, (with-name-equal-to n) m evaluates to true iff m = n.
  • For all names m, (with-name-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all names m, (with-name-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all names m, (with-name-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.2.8. Syntax

match_name ::=
    "with-any-name"
  | "(" "with-name-equal-to" <name> ")"
  | "(" "with-name-not-equal-to" <name> ")"
  | "(" "with-name-similar-to" <string> ")"
  | "(" "with-name-not-similar-to" <string> ")"
  ;
A type match expression is an expression used to filter search results. The expression is evaluated using the object's set of types as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.3.3. Forms

  • with-any-types
  • (with-types-equal-to n)
  • (with-types-not-equal-to n)
  • (with-types-superset-of n)
  • (with-types-subset-of n)
  • (with-types-overlapping n)
Expressions have the following semantics, given in terms of a match_type_evaluate function:

7.1.8.3.5. Semantics

match_name_evaluate with-any-type s                 ⇒ true
match_name_evaluate (with-types-to t) s             ⇒ s = t
match_name_evaluate (with-types-not-equal-to t) s   ⇒ s ≠ t
match_name_evaluate (with-types-superset-of t) s    ⇒ s ⊆ t
match_name_evaluate (with-types-subset-of t) s      ⇒ s ⊇ t
match_name_evaluate (with-types-overlapping t) s    ⇒ ∃ e. e ∈ t ∧ e ∈ s

7.1.8.3.6. Semantics Explanation

  • An expression with-any-types always evaluates to true.
  • For all descriptions s, (with-types-equal-to t) s evaluates to true iff t = s. Note that sets are not ordered.
  • For all descriptions s, (with-types-not-equal-to t) s evaluates to true iff s ≠ t. Note that sets are not ordered.
  • For all descriptions s, (with-types-subset-of t) s evaluates to true iff s is a subset of t.
  • For all descriptions s, (with-types-superset-of t) s evaluates to true iff s is a superset of t.
  • For all descriptions s, (with-types-overlapping t) s evaluates to true iff there exists some element e that is present in both s and t.

7.1.8.3.7. Syntax

match_type ::=
    "with-any-type"
  | "(" "with-types-equal-to" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-not-equal-to" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-superset-of" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-subset-of" <type-record-identifier> [<type-record-identifier>, ...] ")"
  | "(" "with-types-overlapping" <type-record-identifier> [<type-record-identifier>, ...] ")"
  ;
A description match expression is an expression used to filter search results. The expression is evaluated using the object's description as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.4.3. Forms

  • with-any-description
  • (with-description-equal-to n)
  • (with-description-not-equal-to n)
  • (with-description-similar-to n)
  • (with-description-not-similar-to n)
Expressions have the following semantics, given in terms of a match_description_evaluate function:

7.1.8.4.5. Semantics

match_description_evaluate with-any-description n                 ⇒ true
match_description_evaluate (with-description-equal-to m) n        ⇒ n = m
match_description_evaluate (with-description-not-equal-to m) n    ⇒ n ≠ m
match_description_evaluate (with-description-similar-to m) n      ⇒ n ≃ m
match_description_evaluate (with-description-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.4.6. Semantics Explanation

  • An expression with-any-description always evaluates to true.
  • For all descriptions m, (with-description-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-description-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all descriptions m, (with-description-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all descriptions m, (with-description-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.4.8. Syntax

match_description ::=
    "with-any-description"
  | "(" "with-description-equal-to" <description> ")"
  | "(" "with-description-not-equal-to" <description> ")"
  | "(" "with-description-similar-to" <string> ")"
  | "(" "with-description-not-similar-to" <string> ")"
  ;
A media type match expression is an expression used to filter search results. The expression is evaluated using the object's media type as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.5.3. Forms

  • with-any-mediatype
  • (with-mediatype-equal-to n)
  • (with-mediatype-not-equal-to n)
  • (with-mediatype-similar-to n)
  • (with-mediatype-not-similar-to n)
Expressions have the following semantics, given in terms of a match_mediatype_evaluate function:

7.1.8.5.5. Semantics

match_mediatype_evaluate with-any-mediatype n                 ⇒ true
match_mediatype_evaluate (with-mediatype-equal-to m) n        ⇒ n = m
match_mediatype_evaluate (with-mediatype-not-equal-to m) n    ⇒ n ≠ m
match_mediatype_evaluate (with-mediatype-similar-to m) n      ⇒ n ≃ m
match_mediatype_evaluate (with-mediatype-not-similar-to m) n  ⇒ not (n ≃ m)

7.1.8.5.6. Semantics Explanation

  • An expression with-any-mediatype always evaluates to true.
  • For all media types m, (with-mediatype-equal-to n) m evaluates to true iff m = n.
  • For all media types m, (with-mediatype-not-equal-to n) m evaluates to true iff m ≠ n.
  • For all media types m, (with-mediatype-similar-to n) m evaluates to true iff m is sufficiently similar to n according to an implementation-defined, language-specific similarity function.
  • For all media types m, (with-mediatype-not-similar-to n) m evaluates to true iff m is not sufficiently similar to n according to an implementation-defined, language-specific similarity function.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.5.8. Syntax

match_mediatype ::=
    "with-any-mediatype"
  | "(" "with-mediatype-equal-to" <mediatype> ")"
  | "(" "with-mediatype-not-equal-to" <mediatype> ")"
  | "(" "with-mediatype-similar-to" <string> ")"
  | "(" "with-mediatype-not-similar-to" <string> ")"
  ;
A serial match expression is an expression used to filter search results. The expression is evaluated using the object's serial number as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.6.3. Forms

  • with-any-serial
  • (with-serial-equal-to n)
  • (with-serial-not-equal-to n)
Expressions have the following semantics, given in terms of a match_serial_evaluate function:

7.1.8.6.5. Semantics

match_serial_evaluate with-any-serial n                 ⇒ true
match_serial_evaluate (with-serial-equal-to m) n        ⇒ n = m
match_serial_evaluate (with-serial-not-equal-to m) n    ⇒ n ≠ m

7.1.8.6.6. Semantics Explanation

  • An expression with-any-serial always evaluates to true.
  • For all descriptions m, (with-serial-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-serial-not-equal-to n) m evaluates to true iff m ≠ n.
Specifically, the "similarity" function is currently implemented in terms of PostgreSQL's full text search functionality.

7.1.8.6.8. Syntax

match_serial ::=
    "with-any-serial"
  | "(" "with-serial-equal-to" <serial> ")"
  | "(" "with-serial-not-equal-to" <serial> ")"
  ;
A package match expression is an expression used to filter search results. The expression is evaluated using the object's type package as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.7.3. Forms

  • with-any-package
  • (with-package-equal-to n)
  • (with-package-not-equal-to n)
Expressions have the following semantics, given in terms of a match_package_evaluate function:

7.1.8.7.5. Semantics

match_package_evaluate with-any-package n                 ⇒ true
match_package_evaluate (with-package-equal-to m) n        ⇒ n = m
match_package_evaluate (with-package-not-equal-to m) n    ⇒ n ≠ m

7.1.8.7.6. Semantics Explanation

  • An expression with-any-package always evaluates to true.
  • For all descriptions m, (with-package-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-package-not-equal-to n) m evaluates to true iff m ≠ n.

7.1.8.7.7. Syntax

match_package ::=
    "with-any-package"
  | "(" "with-package-equal-to" <package> ")"
  | "(" "with-package-not-equal-to" <package> ")"
  ;
A field match expression is an expression used to filter search results. The expression is evaluated using the object's field name as input and the object is included in search results if the expression evaluates to true.
An expression takes one of the following forms:

7.1.8.8.3. Forms

  • with-any-field
  • (with-field-equal-to n)
  • (with-field-not-equal-to n)
Expressions have the following semantics, given in terms of a match_field_evaluate function:

7.1.8.8.5. Semantics

match_field_evaluate with-any-field n                 ⇒ true
match_field_evaluate (with-field-equal-to m) n        ⇒ n = m
match_field_evaluate (with-field-not-equal-to m) n    ⇒ n ≠ m

7.1.8.8.6. Semantics Explanation

  • An expression with-any-field always evaluates to true.
  • For all descriptions m, (with-field-equal-to n) m evaluates to true iff m = n.
  • For all descriptions m, (with-field-not-equal-to n) m evaluates to true iff m ≠ n.

7.1.8.8.7. Syntax

match_field ::=
    "with-any-field"
  | "(" "with-field-equal-to" <type-record-field-identifier> ")"
  | "(" "with-field-not-equal-to" <type-record-field-identifier> ")"
  ;
audit-search-begin - Begin searching for audit records.
The audit-search-begin command begins searching for audit records.

7.2.1.3.1. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 10
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.1.3.2. --time-from

Attribute Value
Name --time-from
Type java.time.OffsetDateTime
Default Value 1970-01-01T00:00Z
Cardinality [1, 1]
Description Return audit events later than this date.

7.2.1.3.3. --time-to

Attribute Value
Name --time-to
Type java.time.OffsetDateTime
Default Value +101970-01-01T00:00Z
Cardinality [1, 1]
Description Return audit events earlier than this date.

7.2.1.3.4. --type-equal-to

Attribute Value
Name --type-equal-to
Type java.lang.String
Default Value
Cardinality [0, 1]
Description Filter events by type.

7.2.1.3.5. --type-not-equal-to

Attribute Value
Name --type-not-equal-to
Type java.lang.String
Default Value
Cardinality [0, 1]
Description Filter events by type.

7.2.1.3.6. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [0, 1]
Description Filter events by user.

7.2.1.4.1. Example

$ audit-search-begin
Search results: Page 1 of 1
┌────┬──────────────────────────────────────┬────────────────┬─────────────────────────────┬─────────────────────────────────────────────────────────────────────────┐
│ ID │ Owner                                │ Type           │ Time                        │ Data                                                                    │
├────┼──────────────────────────────────────┼────────────────┼─────────────────────────────┼─────────────────────────────────────────────────────────────────────────┤
│ 1  │ c5574d46-7413-43c8-b6db-31001c382ca3 │ USER_LOGGED_IN │ 2023-12-21T11:30:11.171839Z │ {UserAgent=com.io7m.cardant.client/0.0.1-SNAPSHOT, Host=10.1.6.1:53236} │
└────┴──────────────────────────────────────┴────────────────┴─────────────────────────────┴─────────────────────────────────────────────────────────────────────────┘
audit-search-next - Go to the next page of audit events.
The audit-search-next command goes to the next page of audit events.
The command can only be used after the associated begin command.
audit-search-previous - Go to the previous page of audit events.
The audit-search-previous command goes to the previous page of audit events.
The command can only be used after the associated begin command.
bookmark-list - List server bookmarks.
The bookmark-list command lists the local server bookmarks.
bookmark-login - Log in using a bookmark.
The bookmark-login command logs into a server using a bookmark.

7.2.5.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The name of the bookmark.
bookmark-put - Create or update a server bookmark.
The bookmark-put command creates or updates a bookmark.

7.2.6.3.1. --hostname

Attribute Value
Name --hostname
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The hostname of the server.

7.2.6.3.2. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the bookmark.

7.2.6.3.3. --password

Attribute Value
Name --password
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The password for the server.

7.2.6.3.4. --port

Attribute Value
Name --port
Type java.lang.Integer
Default Value 30000
Cardinality [1, 1]
Description The port used for the server.

7.2.6.3.5. --tls

Attribute Value
Name --tls
Type java.lang.Boolean
Default Value false
Cardinality [1, 1]
Description Whether to use TLS to connect to the server.

7.2.6.3.6. --user

Attribute Value
Name --user
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The username for the server.
bookmark-remove - Remove a server bookmark.
The bookmark-remove command removes a bookmark.

7.2.7.3.1. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The name of the bookmark.
file-get - Download a file.
The file-get command downloads a file from the server.

7.2.8.3.1. --download-to

Attribute Value
Name --download-to
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description If specified, the file will be downloaded to this path.

7.2.8.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.
file-put - Upload a file.
The file-put command creates or updates a file on the server.

7.2.9.3.1. --content-type

Attribute Value
Name --content-type
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The content type (inferred if not specified).

7.2.9.3.2. --description

Attribute Value
Name --description
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The file description.

7.2.9.3.3. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The file.

7.2.9.3.4. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.
file-search-begin - Start searching for files.
The file-search-begin command begins searching for files on the server.
Files can be filtered based on matching their media types against a given media type match expression.
Files can be filtered based on matching their descriptions against a given description match expression.

7.2.10.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include files that have descriptions matching the given expression.

7.2.10.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Long
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.10.3.3. --mediatype-match

Attribute Value
Name --mediatype-match
Type com.io7m.cardant.model.CAMediaTypeMatch
Default Value with-any-mediatype
Cardinality [1, 1]
Description Only include files that have media types matching the given expression.

7.2.10.3.4. --size-maximum

Attribute Value
Name --size-maximum
Type java.lang.Long
Default Value 9223372036854775807
Cardinality [1, 1]
Description The maximum file size.

7.2.10.3.5. --size-minimum

Attribute Value
Name --size-minimum
Type java.lang.Long
Default Value 0
Cardinality [1, 1]
Description The minimum file size.
file-search-next - Go to the next page of files.
The file-search-next command goes to the next page of file search results.
The command can only be used after the associated begin command.
file-search-previous - Go to the previous page of files.
The file-search-previous command goes to the previous page of file search results.
The command can only be used after the associated begin command.
files-recent - List the recent files.
The files-recent command lists the files recently used by shell commands such as file-put.
help - Display help for a given command.
The help command displays help for the given command.

7.2.14.3.1. Example

[cardant]$ help file-put
cardant: usage: file-put [named-arguments ...]

  Upload a file.

  Named parameters:
    --content-type
      Description       : The content type (inferred if not specified).
      Type              : String
      Cardinality       : [0, 1]; Specify at most once.
      Syntax            : <any sequence of characters>
    --description
      Description       : The file description.
      Type              : String
      Cardinality       : [0, 1]; Specify at most once.
      Syntax            : <any sequence of characters>
  * --file
      Description       : The file.
      Type              : Path
      Cardinality       : [1]; Specify exactly once.
      Syntax            : <platform-specific path syntax>
  * --id
      Description       : The file ID.
      Type              : CAFileID
      Cardinality       : [1]; Specify exactly once.
      Syntax            : [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}

  The command does not accept any positional arguments.
item-attachment-add - Add or update an attachment on an item.
The item-attachment-add command adds an attachment to an item.

7.2.15.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.15.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.15.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
item-attachment-remove - Remove an attachment from an item.
The item-attachment-remove command removes an attachment from an item.

7.2.16.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.16.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.16.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
item-create - Create an item.
The item-create command creates a new item.

7.2.17.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [0, 1]
Description The item ID.

7.2.17.3.2. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The item name.
item-get - Retrieve an item.
The item-get command retrieves an item.

7.2.18.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.
item-metadata-put - Add or update metadata on an item.
The item-metadata-put command adds or updates metadata on an item.

7.2.19.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.19.3.2. --metadata

Attribute Value
Name --metadata
Type com.io7m.cardant.model.CAMetadataType
Default Value []
Cardinality [0, N]
Description The metadata key.
item-metadata-remove - Remove metadata from an item.
The item-metadata-remove command removes metadata from an item.

7.2.20.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.20.3.2. --key

Attribute Value
Name --key
Type com.io7m.cardant.model.CATypeRecordFieldIdentifier
Default Value []
Cardinality [1, N]
Description The metadata key.
item-search-begin - Start searching for items.
The item-search-begin command begins searching for items.
Items can be filtered based on matching their names against a given name match expression.
Items can be filtered based on matching their descriptions against a given description match expression.
Items can be filtered based on matching their types against a given type match expression.

7.2.21.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include items that have descriptions matching the given expression.

7.2.21.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.21.3.3. --location-match

Attribute Value
Name --location-match
Type com.io7m.cardant.model.CALocationMatchType
Default Value any-location
Cardinality [1, 1]
Description Only include items in locations matching the given expression.

7.2.21.3.4. --metadata-match

Attribute Value
Name --metadata-match
Type com.io7m.cardant.model.CAMetadataElementMatchType
Default Value anything
Cardinality [1, 1]
Description Only include items with metadata matching the given expression.

7.2.21.3.5. --name-match

Attribute Value
Name --name-match
Type com.io7m.cardant.model.CANameMatchFuzzy
Default Value with-any-name
Cardinality [1, 1]
Description Only include items that have names matching the given expression.

7.2.21.3.6. --serial-match

Attribute Value
Name --serial-match
Type com.io7m.cardant.model.CAItemSerialMatch
Default Value with-any-serial
Cardinality [1, 1]
Description Only include items with serial numbers matching the given expression.

7.2.21.3.7. --type-match

Attribute Value
Name --type-match
Type com.io7m.cardant.model.CATypeMatch
Default Value with-any-type
Cardinality [1, 1]
Description Only include items that have types matching the given expression.
item-search-next - Go to the next page of items.
The item-search-next command goes to the next page of item search results.
The command can only be used after the associated begin command.
item-search-previous - Go to the previous page of items.
The item-search-previous command goes to the previous page of item search results.
The command can only be used after the associated begin command.
item-types-assign - Assign types to an item.
The item-types-assign command assigns types to an item.

7.2.24.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.24.3.2. --type

Attribute Value
Name --type
Type com.io7m.cardant.model.CATypeRecordIdentifier
Default Value []
Cardinality [0, N]
Description The item types.
item-types-revoke - Revoke types from an item.
The item-types-revoke command revokes types from an item.

7.2.25.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.25.3.2. --type

Attribute Value
Name --type
Type com.io7m.cardant.model.CATypeRecordIdentifier
Default Value []
Cardinality [0, N]
Description The item types.
location-attachment-add - Add or update an attachment on an location.
The location-attachment-add command adds an attachment to a location.

7.2.26.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.26.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.26.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
location-attachment-remove - Remove an attachment from an location.
The location-attachment-remove command removes an attachment from a location.

7.2.27.3.1. --file-id

Attribute Value
Name --file-id
Type com.io7m.cardant.model.CAFileID
Default Value
Cardinality [1, 1]
Description The file ID.

7.2.27.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.27.3.3. --relation

Attribute Value
Name --relation
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The attachment relation.
location-get - Retrieve a location.
The location-get command retrieves a location.

7.2.28.3.1. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.
location-list - List locations.
The location-list command lists locations.
location-put - Create or update a location.
The location-put command creates or updates a location.

7.2.30.3.1. --detach

Attribute Value
Name --detach
Type java.lang.Boolean
Default Value
Cardinality [0, 1]
Description Detach the location from its parent.

7.2.30.3.2. --id

Attribute Value
Name --id
Type com.io7m.cardant.model.CALocationID
Default Value d37d0dd8-8f98-4f55-80f7-752471271bb3
Cardinality [1, 1]
Description The location ID.

7.2.30.3.3. --name

Attribute Value
Name --name
Type java.lang.String
Default Value
Cardinality [0, 1]
Description The location name.

7.2.30.3.4. --parent

Attribute Value
Name --parent
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [0, 1]
Description The parent location ID.
login - Log in.
The login command logs in.
logout - Log out.
The logout command logs out.
roles-assign - Assign roles to the given user.
The roles-assign command assigns roles to a user.

7.2.33.3.1. --role

Attribute Value
Name --role
Type com.io7m.medrina.api.MRoleName
Default Value []
Cardinality [0, N]
Description The role name.

7.2.33.3.2. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
roles-get - Return the set of roles held by the given user.
The roles-get command retrieves roles for a user.

7.2.34.3.1. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
roles-revoke - Revoke roles from the given user.
The roles-revoke command revokes roles from a user.

7.2.35.3.1. --role

Attribute Value
Name --role
Type com.io7m.medrina.api.MRoleName
Default Value []
Cardinality [0, N]
Description The role name.

7.2.35.3.2. --user

Attribute Value
Name --user
Type com.io7m.cardant.model.CAUserID
Default Value
Cardinality [1, 1]
Description The user ID.
self - Return details about the current user.
The self command returns the current user's ID and roles.

7.2.36.3.1. Example

[cardant]$ self
User ID: c5574d46-7413-43c8-b6db-31001c382ca3
┌────────────────────────────────────────────────────────────────────────────────┐
│ Role                                                                           │
├────────────────────────────────────────────────────────────────────────────────┤
│ audit.reader                                                                   │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.admin                                                                │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.files.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.reader                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.items.writer                                                         │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.reader                                                     │
├────────────────────────────────────────────────────────────────────────────────┤
│ inventory.locations.writer                                                     │
└────────────────────────────────────────────────────────────────────────────────┘
set - Set shell options.
The set command sets shell options.

7.2.37.3.1. --formatter

Attribute Value
Name --formatter
Type com.io7m.cardant.shell.internal.CAShellCmdSet.Formatter
Default Value
Cardinality [0, 1]
Description Set the shell formatter.

7.2.37.3.2. --terminate-on-errors

Attribute Value
Name --terminate-on-errors
Type java.lang.Boolean
Default Value
Cardinality [0, 1]
Description Terminate execution on the first command that returns an error.
stock-reposit-remove - Remove a stock instance.
The stock-reposit-remove command removes stock instances.

7.2.38.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.38.4.1. Example

[cardant]$ stock-reposit-remove --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297
stock-reposit-serial-introduce - Add an instance of an item to a location.
The stock-reposit-serial-introduce command introduces serial stock instances.

7.2.39.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.39.3.2. --item

Attribute Value
Name --item
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.39.3.3. --location

Attribute Value
Name --location
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.39.3.4. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.39.4.1. Example

[cardant]$ stock-reposit-serial-introduce \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --item 98725a33-5202-4143-820e-75b60a1df4d3 \
  --location 2bbc8132-cae3-4d51-95a0-0ab5318b3745 \
  --serial manufacturer_serial:91FA61CC
stock-reposit-serial-move - Move an instance of an item between locations.
The stock-reposit-serial-move command moves serial stock instances.

7.2.40.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.40.3.2. --location-to

Attribute Value
Name --location-to
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The destination location ID.

7.2.40.4.1. Example

[cardant]$ stock-reposit-serial-move \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --location-to 2bbc8132-cae3-4d51-95a0-0ab5318b3745
stock-reposit-serial-number-add - Add a serial number to a stock instance.
The stock-reposit-serial-number-add command adds serial numbers to a serial stock instance.

7.2.41.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.41.3.2. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.41.4.1. Example

[cardant]$ stock-reposit-serial-number-add \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --serial manufacturer_serial:33CBE10A
stock-reposit-serial-number-remove - Remove a serial number from a stock instance.
The stock-reposit-serial-number-remove command removes serial numbers from stock instances.

7.2.42.3.1. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.42.3.2. --serial

Attribute Value
Name --serial
Type com.io7m.cardant.model.CAItemSerial
Default Value
Cardinality [1, 1]
Description The item serial number.

7.2.42.4.1. Example

[cardant]$ stock-reposit-serial-number-remove \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --serial manufacturer_serial:33CBE10A
stock-reposit-set-add - Add stock instances to locations.
The stock-reposit-set-add command adds more items to existing set stock instances.

7.2.43.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to add.

7.2.43.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.43.4.1. Example

[cardant]$ stock-reposit-set-add \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --count 100
stock-reposit-set-introduce - Introduces instances of items to locations.
The stock-reposit-set-introduce command creates set stock instances.

7.2.44.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to introduce.

7.2.44.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.44.3.3. --item

Attribute Value
Name --item
Type com.io7m.cardant.model.CAItemID
Default Value
Cardinality [1, 1]
Description The item ID.

7.2.44.3.4. --location

Attribute Value
Name --location
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The location ID.

7.2.44.4.1. Example

[cardant]$ stock-reposit-set-introduce \
  --instance 3cb641ac-182f-4f44-98f6-a3e0fe752297 \
  --location 55311cea-052f-4f72-9e34-bc01d0e43fee \
  --item 102c2df9-bbb4-4e5d-948f-0d8620704b97 \
  --count 100
stock-reposit-set-move - Move instances of items between locations.
The stock-reposit-set-move command moves items between set stock instances.

7.2.45.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to remove.

7.2.45.3.2. --instance-from

Attribute Value
Name --instance-from
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The source stock instance ID.

7.2.45.3.3. --instance-to

Attribute Value
Name --instance-to
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The target stock instance ID.

7.2.45.3.4. --location-to

Attribute Value
Name --location-to
Type com.io7m.cardant.model.CALocationID
Default Value
Cardinality [1, 1]
Description The destination location ID.

7.2.45.4.1. Example

[cardant]$ stock-reposit-set-move \
  --instance-from 0b041ff1-4bbe-4265-b0f2-51f0c5ff6757 \
  --instance-to d7c18055-cadb-4701-aa3d-9207711f6c8a
  --location-to 55311cea-052f-4f72-9e34-bc01d0e43fee \
  --count 50
stock-reposit-set-remove - Remove stock instances from locations.
The stock-reposit-set-remove command removes items from set stock instances.

7.2.46.3.1. --count

Attribute Value
Name --count
Type java.lang.Long
Default Value
Cardinality [1, 1]
Description The number of instances of the item to remove.

7.2.46.3.2. --instance

Attribute Value
Name --instance
Type com.io7m.cardant.model.CAStockInstanceID
Default Value
Cardinality [1, 1]
Description The stock instance ID.

7.2.46.4.1. Example

[cardant]$ stock-reposit-set-remove \
  --instance 0b041ff1-4bbe-4265-b0f2-51f0c5ff6757 \
  --count 50
stock-search-begin - Start searching for stock.
The stock-search-begin command begins searching for stock.

7.2.47.3.1. --exclude-stock-kind

Attribute Value
Name --exclude-stock-kind
Type com.io7m.cardant.model.CAStockOccurrenceKind
Default Value []
Cardinality [0, N]
Description Exclude stock occurrences of the given kinds.

7.2.47.3.2. --item-match

Attribute Value
Name --item-match
Type com.io7m.cardant.model.CAItemIDMatch
Default Value with-any-item
Cardinality [1, 1]
Description Only include items with IDs matching the given expression.

7.2.47.3.3. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.

7.2.47.3.4. --location-match

Attribute Value
Name --location-match
Type com.io7m.cardant.model.CALocationMatchType
Default Value any-location
Cardinality [1, 1]
Description Only include stock in locations matching the given expression.

7.2.47.4.1. Example

[cardant]$ stock-search-begin
stock-search-next - Go to the next page of stock.
The stock-search-next command returns the next page of search results.

7.2.48.3.1. Example

[cardant]$ stock-search-next
stock-search-previous - Go to the previous page of stock.
The stock-search-previous command returns the previous page of search results.

7.2.49.3.1. Example

[cardant]$ stock-search-previous
syntax-list - List the available syntax definitions.
The syntax-list command lists all the known syntax rules.

7.2.50.3.1. Example

[cardant]$ syntax-list
┌───────────────────────────────────────────────────────────────────────────────────┐
│ Name                                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-equal-to                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-match                                                                 │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-not-equal-to                                                          │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-not-similar-to                                                        │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-similar-to                                                            │
├───────────────────────────────────────────────────────────────────────────────────┤
│ description-with-any                                                              │
├───────────────────────────────────────────────────────────────────────────────────┤
...
The command has no parameters.
syntax-show - Show the given syntax definition.
The syntax-show command displays definitions and/or examples for the given syntax rule.

7.2.51.3.1. Example

[cardant]$ syntax-show --rule metadata-type-match
metadata-type-match :=
  metadata-type-any
  | metadata-type-equal-to
  | metadata-type-not-equal-to
metadata-type-any :=
  with-any-type
metadata-type-equal-to :=
  (with-type-equal-to <type>)
metadata-type-not-equal-to :=
  (with-type-not-equal-to <type>)

[cardant]$ syntax-show --rule metadata-type-match --example true
[with-type-equal-to "com.io7m:t"]

[with-type-not-equal-to "com.io7m:t"]

7.2.51.4.1. --example

Attribute Value
Name --example
Type java.lang.Boolean
Default Value false
Cardinality [1, 1]
Description Show a syntax example.

7.2.51.4.2. --rule

Attribute Value
Name --rule
Type java.lang.String
Default Value
Cardinality [1, 1]
Description The syntax rule name.
type-package-get-text - Retrieve the text of a type package.
The type-package-get-text command retrieves the raw text of an installed type package.

7.2.52.3.1. --name

Attribute Value
Name --name
Type com.io7m.lanark.core.RDottedName
Default Value
Cardinality [1, 1]
Description The type package name.

7.2.52.3.2. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

7.2.52.3.3. --version

Attribute Value
Name --version
Type com.io7m.verona.core.Version
Default Value
Cardinality [1, 1]
Description The type package version.

7.2.52.4.1. Example

[cardant]$ type-package-get-text --name com.io7m.example --version 1.0.0 --output file.xml
type-package-install - Install a type package.
The type-package-install command installs a type package from a file. Once installed, type packages may be upgraded or uninstalled.

7.2.53.3.1. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The type package file.
type-package-schema - Retrieve the text of the type package schema.
The type-package-schema command retrieves the text of the type package schema.

7.2.54.3.1. --output

Attribute Value
Name --output
Type java.nio.file.Path
Default Value
Cardinality [0, 1]
Description The output file.

7.2.54.4.1. Example

[cardant]$ type-package-schema
<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:p="com.io7m.cardant:type_packages:1"
            targetNamespace="com.io7m.cardant:type_packages:1">

  <xsd:simpleType name="UnqualifiedNameType">
    <xsd:annotation>
...
type-package-search-begin - Start searching for type packages
The type-package-search-begin command starts searching for installed type packages.
Packages can be filtered based on matching their descriptions against a given description match expression.

7.2.55.3.1. --description-match

Attribute Value
Name --description-match
Type com.io7m.cardant.model.CADescriptionMatch
Default Value with-any-description
Cardinality [1, 1]
Description Only include types that have descriptions matching the given expression.

7.2.55.3.2. --limit

Attribute Value
Name --limit
Type java.lang.Integer
Default Value 100
Cardinality [1, 1]
Description The maximum number of results per page.
type-package-search-next - Go to the next page of type packages.
The type-package-search-next command goes to the next page of type packages.
The command can only be used after the associated begin command.
type-package-search-previous - Go to the previous page of type packages.
The type-package-search-previous command goes to the previous page of type packages.
The command can only be used after the associated begin command.
type-package-uninstall - Uninstall a type package.
The type-package-uninstall command uninstalls an installed type package.

7.2.58.3.1. --behavior

Attribute Value
Name --behavior
Type com.io7m.cardant.model.type_package.CATypePackageTypeRemovalBehavior
Default Value TYPE_REMOVAL_FAIL_IF_TYPES_REFERENCED
Cardinality [1, 1]
Description The uninstall behavior.

7.2.58.3.2. --name

Attribute Value
Name --name
Type com.io7m.lanark.core.RDottedName
Default Value
Cardinality [1, 1]
Description The type package name.

7.2.58.3.3. --version

Attribute Value
Name --version
Type com.io7m.verona.core.Version
Default Value
Cardinality [1, 1]
Description The type package version.
type-package-upgrade - Upgrade a type package.
The type-package-upgrade command upgrades (or optionally downgrades) an installed type package.

7.2.59.3.1. --file

Attribute Value
Name --file
Type java.nio.file.Path
Default Value
Cardinality [1, 1]
Description The type package file.

7.2.59.3.2. --type-removal-behavior

Attribute Value
Name --type-removal-behavior
Type com.io7m.cardant.model.type_package.CATypePackageTypeRemovalBehavior
Default Value TYPE_REMOVAL_FAIL_IF_TYPES_REFERENCED
Cardinality [1, 1]
Description The type removal behavior.

7.2.59.3.3. --version-behavior

Attribute Value
Name --version-behavior
Type com.io7m.cardant.model.type_package.CATypePackageVersionBehavior
Default Value VERSION_DISALLOW_DOWNGRADES
Cardinality [1, 1]
Description The version behavior.
version - Display the shell version.
The version command displays the shell version.
The Inventory API service exposes one or more versions of the Inventory protocol. The service uses the verdant protocol to advertise which versions of the Inventory protocol are available. Executing a GET request to the root endpoint will yield a verdant message showing which versions of the Inventory protocol are available. The Inventory protocol is assigned the protocol identifier 8ee23158-f8db-317a-a58b-45bd9d702040.
As an example, the following shows that the Inventory protocol version 1 is available at /inventory/1/0/:

8.1.1.3. Verdant Example

$ curl https://cardant.example.com:30000/ | hexdump
0000:0000  00 00 00 01 00 00 00 01  8e e2 31 58 f8 db 31 7a  |..........1X..1z|
0000:0010  a5 8b 45 bd 9d 70 20 40  00 00 00 01 00 00 00 00  |..E..p @........|
0000:0020  00 00 00 0f 2f 69 6e 76  65 6e 74 6f 72 79 2f 31  |..../inventory/1|
0000:0030  2f 30 2f                                          |/0/|
The Inventory API service exposes a health check endpoint at /health. The endpoint returns a 200 status code and the string OK if the server's most recent internal health checks succeeded. The server returns a 500 status code and string not equal to OK if the server's most recent internal health checks failed. In both cases, the string is returned directly as a text/plain UTF-8 value.
The version 1 Inventory protocol uses cedarbridge encoded messages over HTTP(s).
Send an CAI1CommandLogin command to /inventory/1/0/login. If the login succeeds, a cookie named CARDANT_INVENTORY_SESSION will be set. This cookie must be included with all subsequent requests.
After logging in successfully, send commands of type CAI1Command* to /inventory/1/0/command. Failed commands will yield a value of type CAI1ResponseError, whilst successful results will yield values of type CAI1Response*.
It can sometimes be desirable to send sets of commands that must execute atomically; if a single command in the set fails, it must be as if none of the commands were executed.
After logging in successfully, a sequence of commands of type CAI1Command* can be sent to /inventory/1/0/transaction. Each command must be prefixed with its serialized length as a 32-bit unsigned big-endian integer, and the sequence of commands must be terminated with a 32-bit unsigned big-endian value of zero.
The response from the /inventory/1/0 /transaction endpoint will be formatted in the same manner, where each element in the sequence is a value of type CAI1Response for the corresponding command in the original sequence. If any of the values in the sequence are CAI1ResponseError values, the transaction was rolled back by the server and not committed.

8.1.4.1. Schemas

;
; Copyright © 2023 Mark Raynsford <code@io7m.com> https://www.io7m.com
;
; Permission to use, copy, modify, and/or distribute this software for any
; purpose with or without fee is hereby granted, provided that the above
; copyright notice and this permission notice appear in all copies.
;
; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
; SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
; IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;

[language cedarbridge 1 0]

[package com.io7m.cardant.protocol.inventory.cb]

[import com.io7m.cedarbridge cb]
[import com.io7m.cedarbridge.time ct]

[variant CAI1ComparisonExact
  [parameter T]
  [case Anything]
  [case IsEqualTo    [field value T]]
  [case IsNotEqualTo [field value T]]
]

[variant CAI1ComparisonFuzzy
  [parameter T]
  [case Anything]
  [case IsEqualTo      [field value T]]
  [case IsNotEqualTo   [field value T]]
  [case IsSimilarTo    [field value T]]
  [case IsNotSimilarTo [field value T]]
]

[variant CAI1ComparisonSet
  [parameter T]
  [case Anything]
  [case IsEqualTo     [field value [cb:List T]]]
  [case IsNotEqualTo  [field value [cb:List T]]]
  [case IsSubsetOf    [field value [cb:List T]]]
  [case IsSupersetOf  [field value [cb:List T]]]
  [case IsOverlapping [field value [cb:List T]]]
]

[documentation CAI1Id "An identifier value."]
[variant CAI1Id
  [case CAI1FileID           [field id cb:UUID]]
  [case CAI1ItemID           [field id cb:UUID]]
  [case CAI1LocationID       [field id cb:UUID]]
  [case CAI1UserID           [field id cb:UUID]]
  [case CAI1StockInstanceID  [field id cb:UUID]]
]

[documentation CAI1ItemSerial "A serial number."]
[record CAI1ItemSerial
  [field type  cb:String]
  [field value cb:String]]

[documentation CAI1IncludeDeleted "Include deleted data in search results."]
[variant CAI1IncludeDeleted
  [documentation IncludeOnlyLive "Include only live data."]
  [case IncludeOnlyLive]
  [documentation IncludeOnlyDeleted "Include only deleted data."]
  [case IncludeOnlyDeleted]
  [documentation IncludeLiveAndDeleted "Include both live and deleted data."]
  [case IncludeLiveAndDeleted]
]

[documentation CAI1File "A file."]
[variant CAI1File
  [case CAI1FileWithoutData
    [documentation id "The file ID."]
    [field id cb:UUID]
    [documentation description "The file description."]
    [field description cb:String]
    [documentation mediaType "The media type."]
    [field mediaType cb:String]
    [documentation size "The file size."]
    [field size cb:IntegerUnsigned64]
    [documentation hashAlgorithm "The hash algorithm name."]
    [field hashAlgorithm cb:String]
    [documentation hashValue "The hash value."]
    [field hashValue cb:String]]
  [case CAI1FileWithData
    [documentation id "The file ID."]
    [field id cb:UUID]
    [documentation description "The file description."]
    [field description cb:String]
    [documentation mediaType "The media type."]
    [field mediaType cb:String]
    [documentation size "The file size."]
    [field size cb:IntegerUnsigned64]
    [documentation hashAlgorithm "The hash algorithm name."]
    [field hashAlgorithm cb:String]
    [documentation hashValue "The hash value."]
    [field hashValue cb:String]
    [documentation data "The file data."]
    [field data cb:ByteArray]]
]

[documentation CAI1Metadata "A metadata value."]
[variant CAI1Metadata
  [case Integral
    [documentation key "The metadata value key."]
    [field key CAI1TypeRecordFieldIdentifier]
    [documentation value "The metadata value."]
    [field value cb:IntegerSigned64]
  ]
  [case Text
    [documentation key "The metadata value key."]
    [field key CAI1TypeRecordFieldIdentifier]
    [documentation value "The metadata value."]
    [field value cb:String]
  ]
  [case Time
    [documentation key "The metadata value key."]
    [field key CAI1TypeRecordFieldIdentifier]
    [documentation value "The metadata value."]
    [field value ct:OffsetDateTime]
  ]
  [case Monetary
    [documentation key "The metadata value key."]
    [field key CAI1TypeRecordFieldIdentifier]
    [documentation value "The metadata value."]
    [field value cb:String]
    [documentation currency "The metadata currency unit."]
    [field currency cb:String]
  ]
  [case Real
    [documentation key "The metadata value key."]
    [field key CAI1TypeRecordFieldIdentifier]
    [documentation value "The metadata value."]
    [field value cb:Float64]
  ]
]

[documentation CAI1AttachmentKey "The values that uniquely identify an attachment on an object."]
[record CAI1AttachmentKey
  [documentation id "The file ID."]
  [field id cb:UUID]
  [documentation relation "The relation."]
  [field relation cb:String]
]

[documentation CAI1Attachment "An item attachment."]
[record CAI1Attachment
  [documentation file "The file ID."]
  [field file CAI1File]
  [documentation relation "The relation."]
  [field relation cb:String]
]

[documentation CAI1Item "An item."]
[record CAI1Item
  [documentation id "The item ID."]
  [field id cb:UUID]
  [documentation name "The item name."]
  [field name cb:String]
  [documentation created "The creation time"]
  [field created ct:OffsetDateTime]
  [documentation updated "The updated time"]
  [field updated ct:OffsetDateTime]
  [documentation metadata "The item metadata."]
  [field metadata [cb:Map CAI1TypeRecordFieldIdentifier CAI1Metadata]]
  [documentation attachments "The item attachments."]
  [field attachments [cb:Map CAI1AttachmentKey CAI1Attachment]]
  [documentation types "The item types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1LocationMatch "The behaviour requested for matching locations."]
[variant CAI1LocationMatch
  [documentation CAI1LocationExact "Only consider the exact given location."]
  [case CAI1LocationExact
    [field locationId cb:UUID]]
  [documentation CAI1LocationWithDescendants "Consider the given location and all descendants of the given location."]
  [case CAI1LocationWithDescendants
    [field locationId cb:UUID]]
  [documentation CAI1LocationAny "Consider all locations."]
  [case CAI1LocationAny]
]

[documentation CAI1StockReposit "The type of item reposit operations."]
[variant CAI1StockReposit
  [documentation CAI1StockRepositSetIntroduce "An operation that adds a set of items to a storage location."]
  [case CAI1StockRepositSetIntroduce
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation itemId "The item."]
    [field itemId cb:UUID]
    [documentation locationId "The location ID."]
    [field locationId cb:UUID]
    [documentation count "The count."]
    [field count cb:IntegerUnsigned64]
  ]

  [documentation CAI1StockRepositSetAdd "An operation that adds a set of items to an instance."]
  [case CAI1StockRepositSetAdd
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation count "The count."]
    [field count cb:IntegerUnsigned64]
  ]

  [documentation CAI1StockRepositSetMove "An operation that moves a set of items from one storage location to another."]
  [case CAI1StockRepositSetMove
    [documentation instanceSource "The source instance."]
    [field instanceSource cb:UUID]
    [documentation instanceTarget "The target instance."]
    [field instanceTarget cb:UUID]
    [documentation locationTo "The target location."]
    [field locationTo cb:UUID]
    [documentation count "The count."]
    [field count cb:IntegerUnsigned64]
  ]

  [documentation CAI1StockRepositSetRemove "An operation that removes a set of items from a storage location."]
  [case CAI1StockRepositSetRemove
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation count "The count."]
    [field count cb:IntegerUnsigned64]
  ]

  [documentation CAI1StockRepositSerialIntroduce "An operation that adds a single identified item to a storage location."]
  [case CAI1StockRepositSerialIntroduce
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation itemId "The item."]
    [field itemId cb:UUID]
    [documentation locationId "The location ID."]
    [field locationId cb:UUID]
    [documentation serial "The serial number."]
    [field serial CAI1ItemSerial]
  ]

  [documentation CAI1StockRepositSerialMove "An operation that moves a single identified item between storage locations."]
  [case CAI1StockRepositSerialMove
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation locationTo "The target location."]
    [field locationTo cb:UUID]
  ]

  [documentation CAI1StockRepositSerialRemove "An operation that removes a single identified item."]
  [case CAI1StockRepositSerialRemove
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
  ]

  [documentation CAI1StockRepositSerialNumberAdd "An operation that adds a serial number to an instance."]
  [case CAI1StockRepositSerialNumberAdd
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation serial "The serial number."]
    [field serial CAI1ItemSerial]
  ]

  [documentation CAI1StockRepositSerialNumberRemove "An operation that removes a serial number from an instance."]
  [case CAI1StockRepositSerialNumberRemove
    [documentation instanceId "The instance."]
    [field instanceId cb:UUID]
    [documentation serial "The serial number."]
    [field serial CAI1ItemSerial]
  ]
]

[documentation CAI1LocationSummary "A summary of a location."]
[record CAI1LocationSummary
  [field id cb:UUID]
  [field parent [cb:Option cb:UUID]]
  [field path [cb:List cb:String]]
  [documentation created "The creation time"]
  [field created ct:OffsetDateTime]
  [documentation updated "The updated time"]
  [field updated ct:OffsetDateTime]
]

[documentation CAI1Location "A location."]
[record CAI1Location
  [documentation locationId "The location ID."]
  [field locationId cb:UUID]
  [documentation parent "The location parent."]
  [field parent [cb:Option cb:UUID]]
  [documentation path "The location path."]
  [field path [cb:List cb:String]]
  [documentation created "The creation time"]
  [field created ct:OffsetDateTime]
  [documentation updated "The updated time"]
  [field updated ct:OffsetDateTime]
  [documentation metadata "The item metadata."]
  [field metadata [cb:Map CAI1TypeRecordFieldIdentifier CAI1Metadata]]
  [documentation attachments "The item attachments."]
  [field attachments [cb:Map CAI1AttachmentKey CAI1Attachment]]
  [documentation types "The item types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1ItemColumn "The item column by which to order results."]
[variant CAI1ItemColumn
  [documentation CAI1ById "Order by item ID."]
  [case CAI1ById]
  [documentation CAI1ByName "Order by item name."]
  [case CAI1ByName]
]

[documentation CAI1ItemColumnOrdering "The item column by which to order results."]
[record CAI1ItemColumnOrdering
  [documentation column "The item column."]
  [field column CAI1ItemColumn]
  [documentation ascending "Whether results should be in ascending order."]
  [field ascending cb:Boolean]
]

[documentation CAI1MetadataValueMatch "An expression against which item metadata values are matched."]
[variant CAI1MetadataValueMatch
  [case Anything]
  [case IntegralWithinRange
    [field lower cb:IntegerSigned64]
    [field upper cb:IntegerSigned64]
  ]
  [case RealWithinRange
    [field lower cb:Float64]
    [field upper cb:Float64]
  ]
  [case TimeWithinRange
    [field lower ct:OffsetDateTime]
    [field upper ct:OffsetDateTime]
  ]
  [case MonetaryWithinRange
    [field lower cb:String]
    [field upper cb:String]
  ]
  [case MonetaryWithCurrency
    [field currency cb:String]
  ]
  [case TextExact
    [field exact cb:String]
  ]
  [case TextSearch
    [field search cb:String]
  ]
]

[documentation CAI1MetadataElementMatch "An expression against which item metadata is matched."]
[variant CAI1MetadataElementMatch
  [case And
    [field e0 CAI1MetadataElementMatch]
    [field e1 CAI1MetadataElementMatch]
  ]
  [case Or
    [field e0 CAI1MetadataElementMatch]
    [field e1 CAI1MetadataElementMatch]
  ]
  [case Specific
    [field packageName [CAI1ComparisonExact cb:String]]
    [field typeName [CAI1ComparisonExact cb:String]]
    [field fieldName [CAI1ComparisonExact cb:String]]
    [field value CAI1MetadataValueMatch]
  ]
]

[documentation CAI1ItemSearchParameters "The item search parameters."]
[record CAI1ItemSearchParameters
  [documentation nameMatch "The item name match expression."]
  [field nameMatch [CAI1ComparisonFuzzy cb:String]]
  [documentation descriptionMatch "The item description match expression."]
  [field descriptionMatch [CAI1ComparisonFuzzy cb:String]]
  [documentation typeMatch "The item type match expression."]
  [field typeMatch [CAI1ComparisonSet CAI1TypeRecordIdentifier]]
  [documentation metaMatch "The item metadata match expression."]
  [field metaMatch CAI1MetadataElementMatch]
  [documentation includeDeleted "Include live/deleted data."]
  [field includeDeleted CAI1IncludeDeleted]
  [documentation order "The item result ordering."]
  [field order CAI1ItemColumnOrdering]
  [documentation limit "The item limit."]
  [field limit cb:IntegerUnsigned32]
]

[documentation CAI1FileColumn "The item column by which to order results."]
[variant CAI1FileColumn
  [documentation CAI1ById "Order by file ID."]
  [case CAI1ById]
  [documentation CAI1ByDescription "Order by file description."]
  [case CAI1ByDescription]
]

[documentation CAI1FileColumnOrdering "The file column by which to order results."]
[record CAI1FileColumnOrdering
  [documentation column "The file column."]
  [field column CAI1FileColumn]
  [documentation ascending "Whether results should be in ascending order."]
  [field ascending cb:Boolean]
]

[documentation CAI1SizeRange "A size range."]
[record CAI1SizeRange
  [documentation sizeMinimum "The lower bound (inclusive)."]
  [field sizeMinimum cb:IntegerUnsigned64]
  [documentation sizeMaximum "The upper bound (inclusive)."]
  [field sizeMaximum cb:IntegerUnsigned64]
]

[documentation CAI1TimeRange "An inclusive time range."]
[record CAI1TimeRange
  [field timeLower ct:OffsetDateTime]
  [field timeUpper ct:OffsetDateTime]
]

[documentation CAI1FileSearchParameters "The file search parameters."]
[record CAI1FileSearchParameters
  [documentation search "The file description search query."]
  [field search [CAI1ComparisonFuzzy cb:String]]
  [documentation mediaType "The file media type search query."]
  [field mediaType [CAI1ComparisonFuzzy cb:String]]
  [documentation sizeRange "The file size range query."]
  [field sizeRange CAI1SizeRange]
  [documentation order "The file result ordering."]
  [field order CAI1FileColumnOrdering]
  [documentation limit "The file limit."]
  [field limit cb:IntegerUnsigned32]
]

[documentation CAI1TypeScalarSearchParameters "The scalar type search parameters."]
[record CAI1TypeScalarSearchParameters
  [documentation nameSearch "The type description search query."]
  [field nameSearch [CAI1ComparisonFuzzy cb:String]]
  [documentation descriptionSearch "The type description search query."]
  [field descriptionSearch [CAI1ComparisonFuzzy cb:String]]
  [documentation limit "The limit."]
  [field limit cb:IntegerUnsigned32]
]

[documentation CAI1Page "A page of search results."]
[record CAI1Page
  [parameter T]
  [field items [cb:List T]]
  [field pageIndex cb:IntegerUnsigned32]
  [field pageCount cb:IntegerUnsigned32]
  [field pageFirstOffset cb:IntegerUnsigned64]
]

[documentation CAI1ItemSummary "A summary of an item."]
[record CAI1ItemSummary
  [field id cb:UUID]
  [field name cb:String]
  [documentation created "The creation time"]
  [field created ct:OffsetDateTime]
  [documentation updated "The updated time"]
  [field updated ct:OffsetDateTime]
]

[record CAI1TypeRecordFieldIdentifier
  [field packageName cb:String]
  [field typeName cb:String]
  [field fieldName cb:String]
]

[record CAI1TypeRecordIdentifier
  [field packageName cb:String]
  [field typeName cb:String]
]

[record CAI1TypeScalarIdentifier
  [field packageName cb:String]
  [field typeName cb:String]
]

[documentation CAI1TypeScalar "A scalar type."]
[variant CAI1TypeScalar
  [case Integral
    [documentation name "The type name."]
    [field name CAI1TypeScalarIdentifier]
    [documentation description "The type description."]
    [field description cb:String]
    [field rangeLower cb:IntegerSigned64]
    [field rangeUpper cb:IntegerSigned64]
  ]
  [case Text
    [documentation name "The type name."]
    [field name CAI1TypeScalarIdentifier]
    [documentation description "The type description."]
    [field description cb:String]
    [field pattern cb:String]
  ]
  [case Time
    [documentation name "The type name."]
    [field name CAI1TypeScalarIdentifier]
    [documentation description "The type description."]
    [field description cb:String]
    [field rangeLower ct:OffsetDateTime]
    [field rangeUpper ct:OffsetDateTime]
  ]
  [case Monetary
    [documentation name "The type name."]
    [field name CAI1TypeScalarIdentifier]
    [documentation description "The type description."]
    [field description cb:String]
    [field rangeLower cb:String]
    [field rangeUpper cb:String]
  ]
  [case Real
    [documentation name "The type name."]
    [field name CAI1TypeScalarIdentifier]
    [documentation description "The type description."]
    [field description cb:String]
    [field rangeLower cb:Float64]
    [field rangeUpper cb:Float64]
  ]
]

[documentation CAI1TypeField "A field within a type declaration."]
[record CAI1TypeField
  [documentation name "The type field name."]
  [field name CAI1TypeRecordFieldIdentifier]
  [documentation description "The type field description."]
  [field description cb:String]
  [documentation type "The type of the field."]
  [field type CAI1TypeScalar]
  [documentation required "Whether or not the field is required to be present."]
  [field required cb:Boolean]
]

[documentation CAI1TypeRecord "A type declaration."]
[record CAI1TypeRecord
  [documentation name "The type declaration name."]
  [field name CAI1TypeRecordIdentifier]
  [documentation description "The type declaration description."]
  [field description cb:String]
  [documentation fields "Whether or not the field is required to be present."]
  [field fields [cb:Map CAI1TypeRecordFieldIdentifier CAI1TypeField]]
]

[documentation CAI1TypeRecordSummary "A type declaration summary."]
[record CAI1TypeRecordSummary
  [documentation name "The type declaration name."]
  [field name CAI1TypeRecordIdentifier]
  [documentation description "The type declaration description."]
  [field description cb:String]
]

[documentation CAI1TypeRecordSearchParameters "The declared type search parameters."]
[record CAI1TypeRecordSearchParameters
  [documentation nameSearch "The type description search query."]
  [field nameSearch [CAI1ComparisonFuzzy cb:String]]
  [documentation descriptionSearch "The type description search query."]
  [field descriptionSearch [CAI1ComparisonFuzzy cb:String]]
  [documentation limit "The limit."]
  [field limit cb:IntegerUnsigned32]
]

[documentation CAI1AuditSearchParameters "The audit search parameters."]
[record CAI1AuditSearchParameters
  [documentation owner "Limit to events with the given owner."]
  [field owner [cb:Option cb:UUID]]
  [documentation type "Limit to events with the given type."]
  [field type [CAI1ComparisonExact cb:String]]
  [documentation timeRange "Limit to events in the given time range."]
  [field timeRange CAI1TimeRange]
  [documentation pageSize "The page size."]
  [field pageSize cb:IntegerUnsigned32]
]

[documentation CAI1AuditEvent "An audit event."]
[record CAI1AuditEvent
  [documentation id "The event ID."]
  [field id cb:IntegerUnsigned64]
  [documentation time "The event time."]
  [field time ct:OffsetDateTime]
  [documentation owner "The event owner."]
  [field owner cb:UUID]
  [documentation type "The event type."]
  [field type cb:String]
  [documentation data "The event data."]
  [field data [cb:Map cb:String cb:String]]
]

[documentation CAI1TypePackageSearchParameters "The type package search parameters."]
[record CAI1TypePackageSearchParameters
  [documentation descriptionMatch "The type package description match expression."]
  [field descriptionMatch [CAI1ComparisonFuzzy cb:String]]
  [documentation limit "The item limit."]
  [field limit cb:IntegerUnsigned32]
]

[documentation CAI1Version "A version number."]
[record CAI1Version
  [documentation versionMajor "The major version."]
  [field versionMajor cb:IntegerUnsigned32]
  [documentation versionMinor "The minor version."]
  [field versionMinor cb:IntegerUnsigned32]
  [documentation versionPatch "The patch version."]
  [field versionPatch cb:IntegerUnsigned32]
  [documentation versionQualifier "The version qualifier."]
  [field versionQualifier [cb:Option cb:String]]
]

[documentation CAI1TypePackageIdentifier "The type package identifier."]
[record CAI1TypePackageIdentifier
  [documentation name "The package name."]
  [field name cb:String]
  [documentation version "The package version."]
  [field version CAI1Version]
]

[documentation CAI1TypePackageSummary "The type package summary."]
[record CAI1TypePackageSummary
  [documentation identifier "The package identifier."]
  [field identifier CAI1TypePackageIdentifier]
  [documentation description "The package description."]
  [field description cb:String]
]

[documentation CAI1Error "An error response."]
[record CAI1Error
  [documentation errorCode "The error code."]
  [field errorCode cb:String]
  [documentation message "The error message."]
  [field message cb:String]
  [documentation attributes "The error attributes."]
  [field attributes [cb:Map cb:String cb:String]]
  [documentation remediatingAction "The remediating action, if any."]
  [field remediatingAction [cb:Option cb:String]]
]

[documentation CAI1TypePackageTypeRemovalBehavior "The type package type removal behavior."]
[variant CAI1TypePackageTypeRemovalBehavior
  [case FailIfTypesReferenced]
  [case RevokeTypes]
]

[documentation CAI1TypePackageVersionBehavior "The type package version behavior."]
[variant CAI1TypePackageVersionBehavior
  [case AllowDowngrades]
  [case DisallowDowngrades]
]

[documentation CAI1TypePackageUninstall "The type package uninstall parameters."]
[record CAI1TypePackageUninstall
  [field typeRemovalBehavior CAI1TypePackageTypeRemovalBehavior]
  [field identifier CAI1TypePackageIdentifier]
]

[variant CAI1StockOccurrenceKind
  [case Set]
  [case Serial]
]

[variant CAI1StockOccurrence
  [case Serial
    [field instance cb:UUID]
    [field location CAI1LocationSummary]
    [field item CAI1ItemSummary]
    [field serials [cb:List CAI1ItemSerial]]
  ]
  [case Set
    [field instance cb:UUID]
    [field location CAI1LocationSummary]
    [field item CAI1ItemSummary]
    [field count cb:IntegerUnsigned64]
  ]
]

[documentation CAI1StockSearchParameters "The stock search parameters."]
[record CAI1StockSearchParameters
  [documentation locationMatch "The location match."]
  [field locationMatch CAI1LocationMatch]
  [documentation itemMatch "The item match."]
  [field itemMatch [CAI1ComparisonExact cb:UUID]]
  [documentation includeOccurrences "The kinds of stock occurrences to include."]
  [field includeOccurrences [cb:List CAI1StockOccurrenceKind]]
  [documentation pageSize "The page size."]
  [field pageSize cb:IntegerUnsigned32]
]

;
; Commands.
;

[documentation CAI1CommandLogin "A request to log in."]
[record CAI1CommandLogin
  [documentation userName "The username."]
  [field userName cb:String]
  [documentation password "The password."]
  [field password cb:String]
  [documentation metadata "Extra metadata included with the login request."]
  [field metadata [cb:Map cb:String cb:String]]
]

[documentation CAI1CommandFilePut "Add or update files."]
[record CAI1CommandFilePut
  [documentation file "The file."]
  [field file CAI1File]
]

[documentation CAI1CommandFileDelete "Delete files."]
[record CAI1CommandFileDelete
  [documentation id "The file ID."]
  [field id cb:UUID]
]

[documentation CAI1CommandItemAttachmentAdd "Add item attachments."]
[record CAI1CommandItemAttachmentAdd
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
  [documentation fileId "The file ID."]
  [field fileId cb:UUID]
  [documentation relation "The attachment relation."]
  [field relation cb:String]
]

[documentation CAI1CommandItemAttachmentRemove "Remove item attachments."]
[record CAI1CommandItemAttachmentRemove
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
  [documentation fileId "The file ID."]
  [field fileId cb:UUID]
  [documentation relation "The attachment relation."]
  [field relation cb:String]
]

[documentation CAI1CommandItemCreate "Create a new item."]
[record CAI1CommandItemCreate
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
  [documentation name "The item name."]
  [field name cb:String]
]

[documentation CAI1CommandItemGet "Retrieve an item."]
[record CAI1CommandItemGet
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
]

[documentation CAI1CommandFileGet "Retrieve a file."]
[record CAI1CommandFileGet
  [documentation fileId "The file ID."]
  [field fileId cb:UUID]
]

[documentation CAI1CommandItemLocationsList "List all the locations an item is in, and how many times the item is in them."]
[record CAI1CommandItemLocationsList
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
]

[documentation CAI1CommandItemMetadataPut "Add or update metadata values in an item."]
[record CAI1CommandItemMetadataPut
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
  [documentation metadatas "The item metadatas."]
  [field metadatas [cb:List CAI1Metadata]]
]

[documentation CAI1CommandItemMetadataRemove "Remove metadata values from an item."]
[record CAI1CommandItemMetadataRemove
  [documentation itemId "The item ID."]
  [field itemId cb:UUID]
  [documentation metadatas "The item metadatas."]
  [field metadatas [cb:List CAI1TypeRecordFieldIdentifier]]
]

[documentation CAI1CommandStockReposit "Reposit an item."]
[record CAI1CommandStockReposit
  [documentation reposit "The item reposition."]
  [field reposit CAI1StockReposit]
]

[documentation CAI1CommandItemDelete "Delete items."]
[record CAI1CommandItemDelete
  [documentation item "The items."]
  [field item cb:UUID]
]

[documentation CAI1CommandItemSetName "Update the names of items."]
[record CAI1CommandItemSetName
  [documentation item "The item ID."]
  [field item cb:UUID]
  [documentation name "The item name."]
  [field name cb:String]
]

[documentation CAI1CommandLocationGet "Retrieve a location."]
[record CAI1CommandLocationGet
  [documentation location "The location ID."]
  [field location cb:UUID]
]

[documentation CAI1CommandLocationList "List locations."]
[record CAI1CommandLocationList]

[documentation CAI1CommandLocationPut "Create or update a location."]
[record CAI1CommandLocationPut
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1CommandLocationDelete "Delete locations."]
[record CAI1CommandLocationDelete
  [documentation location "The location."]
  [field location cb:UUID]
]

[documentation CAI1CommandItemSearchBegin "Start searching for items."]
[record CAI1CommandItemSearchBegin
  [documentation parameters "The search parameters."]
  [field parameters CAI1ItemSearchParameters]
]

[documentation CAI1CommandItemSearchNext "Return the next page of search results."]
[record CAI1CommandItemSearchNext]

[documentation CAI1CommandItemSearchPrevious "Return the next page of search results."]
[record CAI1CommandItemSearchPrevious]

[documentation CAI1CommandFileSearchBegin "Start searching for items."]
[record CAI1CommandFileSearchBegin
  [documentation parameters "The search parameters."]
  [field parameters CAI1FileSearchParameters]
]

[documentation CAI1CommandFileSearchNext "Return the next page of search results."]
[record CAI1CommandFileSearchNext]

[documentation CAI1CommandFileSearchPrevious "Return the next page of search results."]
[record CAI1CommandFileSearchPrevious]

[documentation CAI1CommandRolesAssign "Assign a set of roles to a user."]
[record CAI1CommandRolesAssign
  [documentation user "The target user."]
  [field user cb:UUID]
  [documentation roles "The assigned roles."]
  [field roles [cb:List cb:String]]
]

[documentation CAI1CommandRolesRevoke "Revoke a set of roles from a user."]
[record CAI1CommandRolesRevoke
  [documentation user "The target user."]
  [field user cb:UUID]
  [documentation roles "The roles."]
  [field roles [cb:List cb:String]]
]

[documentation CAI1CommandRolesGet "Get the roles for a user."]
[record CAI1CommandRolesGet
  [documentation user "The target user."]
  [field user cb:UUID]
]

[documentation CAI1CommandItemTypesAssign "Assign a set of types to an item."]
[record CAI1CommandItemTypesAssign
  [documentation item "The target item."]
  [field item cb:UUID]
  [documentation types "The assigned types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1CommandItemTypesRevoke "Revoke a set of types from an item."]
[record CAI1CommandItemTypesRevoke
  [documentation item "The target item."]
  [field item cb:UUID]
  [documentation types "The removed types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1CommandLocationMetadataPut "Add or update metadata values in a location."]
[record CAI1CommandLocationMetadataPut
  [documentation locationId "The location ID."]
  [field locationId cb:UUID]
  [documentation metadatas "The location metadatas."]
  [field metadatas [cb:List CAI1Metadata]]
]

[documentation CAI1CommandLocationMetadataRemove "Remove metadata values from a location."]
[record CAI1CommandLocationMetadataRemove
  [documentation locationId "The location ID."]
  [field locationId cb:UUID]
  [documentation metadatas "The location metadatas."]
  [field metadatas [cb:List CAI1TypeRecordFieldIdentifier]]
]

[documentation CAI1CommandLocationTypesAssign "Assign a set of types to a location."]
[record CAI1CommandLocationTypesAssign
  [documentation location "The target location."]
  [field location cb:UUID]
  [documentation types "The assigned types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1CommandLocationTypesRevoke "Revoke a set of types from a location."]
[record CAI1CommandLocationTypesRevoke
  [documentation location "The target location."]
  [field location cb:UUID]
  [documentation types "The removed types."]
  [field types [cb:List CAI1TypeRecordIdentifier]]
]

[documentation CAI1CommandLocationAttachmentAdd "Add location attachments."]
[record CAI1CommandLocationAttachmentAdd
  [documentation locationId "The location ID."]
  [field locationId cb:UUID]
  [documentation fileId "The file ID."]
  [field fileId cb:UUID]
  [documentation relation "The attachment relation."]
  [field relation cb:String]
]

[documentation CAI1CommandLocationAttachmentRemove "Remove location attachments."]
[record CAI1CommandLocationAttachmentRemove
  [documentation locationId "The location ID."]
  [field locationId cb:UUID]
  [documentation fileId "The file ID."]
  [field fileId cb:UUID]
  [documentation relation "The attachment relation."]
  [field relation cb:String]
]

[documentation CAI1CommandAuditSearchBegin "Start searching audit events."]
[record CAI1CommandAuditSearchBegin
  [documentation parameters "The search parameters."]
  [field parameters CAI1AuditSearchParameters]
]

[documentation CAI1CommandAuditSearchNext "Continue searching audit events."]
[record CAI1CommandAuditSearchNext]

[documentation CAI1CommandAuditSearchPrevious "Continue searching audit events."]
[record CAI1CommandAuditSearchPrevious]

[documentation CAI1CommandTypePackageSearchBegin "Start searching type packages."]
[record CAI1CommandTypePackageSearchBegin
  [documentation parameters "The search parameters."]
  [field parameters CAI1TypePackageSearchParameters]
]

[documentation CAI1CommandTypePackageSearchNext "Continue searching type packages."]
[record CAI1CommandTypePackageSearchNext]

[documentation CAI1CommandTypePackageSearchPrevious "Continue searching type packages."]
[record CAI1CommandTypePackageSearchPrevious]

[documentation CAI1CommandTypePackageGetText "Get a type package."]
[record CAI1CommandTypePackageGetText
  [documentation identifier "The type package identifier."]
  [field identifier CAI1TypePackageIdentifier]
]

[documentation CAI1CommandTypePackageInstall "Install a type package."]
[record CAI1CommandTypePackageInstall
  [documentation text "The type package text."]
  [field text cb:String]
]

[documentation CAI1CommandTypePackageUninstall "Uninstall a type package."]
[record CAI1CommandTypePackageUninstall
  [documentation parameters "The uninstall parameters."]
  [field parameters CAI1TypePackageUninstall]
]

[documentation CAI1CommandTypePackageUpgrade "Upgrade a type package."]
[record CAI1CommandTypePackageUpgrade
  [documentation typeRemovalBehavior "The type removal behavior."]
  [field typeRemovalBehavior CAI1TypePackageTypeRemovalBehavior]
  [documentation versionBehavior "The version behavior."]
  [field versionBehavior CAI1TypePackageVersionBehavior]
  [documentation text "The type package text."]
  [field text cb:String]
]

[documentation CAI1CommandStockCount "Count stock."]
[record CAI1CommandStockCount
  [documentation parameters "The search parameters."]
  [field parameters CAI1StockSearchParameters]
]

[documentation CAI1CommandStockSearchBegin "Search stock."]
[record CAI1CommandStockSearchBegin
  [documentation parameters "The search parameters."]
  [field parameters CAI1StockSearchParameters]
]

[documentation CAI1CommandStockSearchNext "Search stock."]
[record CAI1CommandStockSearchNext]

[documentation CAI1CommandStockSearchPrevious "Search stock."]
[record CAI1CommandStockSearchPrevious]

;
; Responses.
;

[documentation CAI1ResponseBlame "A blame assignment."]
[variant CAI1ResponseBlame
  [documentation BlameClient "The client sent a bad response."]
  [case BlameClient]
  [documentation BlameServer "Something went wrong on the server."]
  [case BlameServer]
]

[documentation CAI1ResponseError "An error response."]
[record CAI1ResponseError
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation errorCode "The error code."]
  [field errorCode cb:String]
  [documentation message "The error message."]
  [field message cb:String]
  [documentation attributes "The error attributes."]
  [field attributes [cb:Map cb:String cb:String]]
  [documentation remediatingAction "The remediating action, if any."]
  [field remediatingAction [cb:Option cb:String]]
  [documentation blame "The blame assignment."]
  [field blame CAI1ResponseBlame]
  [documentation extras "The extra errors."]
  [field extras [cb:List CAI1Error]]
]

[documentation CAI1ResponseLogin "A response to CAI1CommandLogin."]
[record CAI1ResponseLogin
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation userId "The ID of the user that logged in."]
  [field userId cb:UUID]
]

[documentation CAI1ResponseFilePut "A response to CAI1CommandFilePut."]
[record CAI1ResponseFilePut
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation file "The file."]
  [field file CAI1File]
]

[documentation CAI1ResponseFileDelete "A response to CAI1CommandFileDelete."]
[record CAI1ResponseFileDelete
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation id "The file ID."]
  [field id cb:UUID]
]

[documentation CAI1ResponseItemAttachmentAdd "A response to CAI1CommandItemAttachmentAdd."]
[record CAI1ResponseItemAttachmentAdd
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseItemAttachmentRemove "A response to CAI1CommandItemAttachmentRemove."]
[record CAI1ResponseItemAttachmentRemove
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseItemCreate "A response to CAI1CommandItemCreate."]
[record CAI1ResponseItemCreate
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseItemGet "A response to CAI1CommandItemGet."]
[record CAI1ResponseItemGet
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseFileGet "A response to CAI1CommandFileGet."]
[record CAI1ResponseFileGet
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation file "The file."]
  [field file CAI1File]
]

[documentation CAI1ResponseItemMetadataPut "A response to CAI1CommandItemMetadataPut."]
[record CAI1ResponseItemMetadataPut
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseItemMetadataRemove "A response to CAI1CommandItemMetadataRemove."]
[record CAI1ResponseItemMetadataRemove
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseStockReposit "A response to CAI1CommandStockReposit."]
[record CAI1ResponseStockReposit
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation stock "The stock."]
  [field stock CAI1StockOccurrence]
]

[documentation CAI1ResponseItemDelete "A response to CAI1CommandItemDelete."]
[record CAI1ResponseItemDelete
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item cb:UUID]
]

[documentation CAI1ResponseItemSetName "A response to CAI1CommandItemSetName."]
[record CAI1ResponseItemSetName
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseLocationGet "A response to CAI1CommandLocationGet."]
[record CAI1ResponseLocationGet
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationList "A response to CAI1CommandLocationList."]
[record CAI1ResponseLocationList
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation locations "The locations."]
  [field locations [cb:Map cb:UUID CAI1LocationSummary]]
]

[documentation CAI1ResponseLocationPut "A response to CAI1CommandLocationPut."]
[record CAI1ResponseLocationPut
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationDelete "A response to CAI1CommandLocationDelete."]
[record CAI1ResponseLocationDelete
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location cb:UUID]
]

[documentation CAI1ResponseItemSearch "A response to CAI1CommandItemSearch."]
[record CAI1ResponseItemSearch
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results."]
  [field results [CAI1Page CAI1ItemSummary]]
]

[documentation CAI1ResponseFileSearch "A response to CAI1CommandFileSearch."]
[record CAI1ResponseFileSearch
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results."]
  [field results [CAI1Page CAI1File]]
]

[documentation CAI1ResponseRolesAssign "A response to CAI1ResponseRolesAssign."]
[record CAI1ResponseRolesAssign
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
]

[documentation CAI1ResponseRolesRevoke "A response to CAI1ResponseRolesRevoke."]
[record CAI1ResponseRolesRevoke
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
]

[documentation CAI1ResponseRolesGet "A response to CAI1ResponseRolesGet."]
[record CAI1ResponseRolesGet
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation roles "The roles."]
  [field roles [cb:List cb:String]]
]

[documentation CAI1ResponseItemTypesAssign "A response to CAI1CommandItemTypesAssign."]
[record CAI1ResponseItemTypesAssign
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseItemTypesRevoke "A response to CAI1CommandItemTypesRevoke."]
[record CAI1ResponseItemTypesRevoke
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation item "The item."]
  [field item CAI1Item]
]

[documentation CAI1ResponseLocationMetadataPut "A response to CAI1CommandLocationMetadataPut."]
[record CAI1ResponseLocationMetadataPut
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationMetadataRemove "A response to CAI1CommandLocationMetadataRemove."]
[record CAI1ResponseLocationMetadataRemove
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationTypesAssign "A response to CAI1CommandLocationTypesAssign."]
[record CAI1ResponseLocationTypesAssign
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationTypesRevoke "A response to CAI1CommandLocationTypesRevoke."]
[record CAI1ResponseLocationTypesRevoke
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationAttachmentAdd "A response to CAI1CommandLocationAttachmentAdd."]
[record CAI1ResponseLocationAttachmentAdd
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseLocationAttachmentRemove "A response to CAI1CommandLocationAttachmentRemove."]
[record CAI1ResponseLocationAttachmentRemove
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation location "The location."]
  [field location CAI1Location]
]

[documentation CAI1ResponseAuditSearch "A response to CAI1CommandAuditSearchBegin."]
[record CAI1ResponseAuditSearch
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results"]
  [field results [CAI1Page CAI1AuditEvent]]
]

[documentation CAI1ResponseTypePackageSearch "A response to CAI1CommandTypePackageSearch."]
[record CAI1ResponseTypePackageSearch
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results."]
  [field results [CAI1Page CAI1TypePackageSummary]]
]

[documentation CAI1ResponseTypePackageGetText "A response to CAI1CommandTypePackageGetText."]
[record CAI1ResponseTypePackageGetText
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results."]
  [field results cb:String]
]

[documentation CAI1ResponseTypePackageInstall "A response to CAI1CommandTypePackageInstall."]
[record CAI1ResponseTypePackageInstall
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation identifier "The identifier."]
  [field identifier CAI1TypePackageIdentifier]
]

[documentation CAI1ResponseTypePackageUninstall "A response to CAI1CommandTypePackageUninstall."]
[record CAI1ResponseTypePackageUninstall
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
]

[documentation CAI1ResponseTypePackageUpgrade "A response to CAI1CommandTypePackageUpgrade."]
[record CAI1ResponseTypePackageUpgrade
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation identifier "The identifier."]
  [field identifier CAI1TypePackageIdentifier]
]

[documentation CAI1ResponseStockCount "A response to CAI1CommandStockCount."]
[record CAI1ResponseStockCount
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation count "The count."]
  [field count cb:IntegerUnsigned64]
]

[documentation CAI1ResponseStockSearch "A response to CAI1CommandStockSearch."]
[record CAI1ResponseStockSearch
  [documentation requestId "The ID of the request that yielded this response."]
  [field requestId cb:UUID]
  [documentation results "The results."]
  [field results [CAI1Page CAI1StockOccurrence]]
]

;
; Events.
;

[documentation CAI1EventUpdated "Data on the server was updated."]
[record CAI1EventUpdated
  [documentation updated "The list of objects that were updated."]
  [field updated [cb:List CAI1Id]]
  [documentation removed "The list of objects that were removed."]
  [field removed [cb:List CAI1Id]]]

;
; Protocol.
;

[documentation CAI "The Inventory protocol."]
[protocol CAI
  [version 1
    [types-added
      CAI1CommandAuditSearchBegin
      CAI1CommandAuditSearchNext
      CAI1CommandAuditSearchPrevious
      CAI1CommandFileDelete
      CAI1CommandFileGet
      CAI1CommandFilePut
      CAI1CommandFileSearchBegin
      CAI1CommandFileSearchNext
      CAI1CommandFileSearchPrevious
      CAI1CommandItemAttachmentAdd
      CAI1CommandItemAttachmentRemove
      CAI1CommandItemCreate
      CAI1CommandItemDelete
      CAI1CommandItemGet
      CAI1CommandItemMetadataPut
      CAI1CommandItemMetadataRemove
      CAI1CommandItemSearchBegin
      CAI1CommandItemSearchNext
      CAI1CommandItemSearchPrevious
      CAI1CommandItemSetName
      CAI1CommandItemTypesAssign
      CAI1CommandItemTypesRevoke
      CAI1CommandLocationAttachmentAdd
      CAI1CommandLocationAttachmentRemove
      CAI1CommandLocationDelete
      CAI1CommandLocationGet
      CAI1CommandLocationList
      CAI1CommandLocationMetadataPut
      CAI1CommandLocationMetadataRemove
      CAI1CommandLocationPut
      CAI1CommandLocationTypesAssign
      CAI1CommandLocationTypesRevoke
      CAI1CommandLogin
      CAI1CommandRolesAssign
      CAI1CommandRolesGet
      CAI1CommandRolesRevoke
      CAI1CommandStockCount
      CAI1CommandStockReposit
      CAI1CommandStockSearchBegin
      CAI1CommandStockSearchNext
      CAI1CommandStockSearchPrevious
      CAI1CommandTypePackageGetText
      CAI1CommandTypePackageInstall
      CAI1CommandTypePackageSearchBegin
      CAI1CommandTypePackageSearchNext
      CAI1CommandTypePackageSearchPrevious
      CAI1CommandTypePackageUninstall
      CAI1CommandTypePackageUpgrade
      CAI1EventUpdated
      CAI1ResponseAuditSearch
      CAI1ResponseError
      CAI1ResponseFileDelete
      CAI1ResponseFileGet
      CAI1ResponseFilePut
      CAI1ResponseFileSearch
      CAI1ResponseItemAttachmentAdd
      CAI1ResponseItemAttachmentRemove
      CAI1ResponseItemCreate
      CAI1ResponseItemDelete
      CAI1ResponseItemGet
      CAI1ResponseItemMetadataPut
      CAI1ResponseItemMetadataRemove
      CAI1ResponseItemSearch
      CAI1ResponseItemSetName
      CAI1ResponseItemTypesAssign
      CAI1ResponseItemTypesRevoke
      CAI1ResponseLocationAttachmentAdd
      CAI1ResponseLocationAttachmentRemove
      CAI1ResponseLocationDelete
      CAI1ResponseLocationGet
      CAI1ResponseLocationList
      CAI1ResponseLocationMetadataPut
      CAI1ResponseLocationMetadataRemove
      CAI1ResponseLocationPut
      CAI1ResponseLocationTypesAssign
      CAI1ResponseLocationTypesRevoke
      CAI1ResponseLogin
      CAI1ResponseRolesAssign
      CAI1ResponseRolesGet
      CAI1ResponseRolesRevoke
      CAI1ResponseStockCount
      CAI1ResponseStockReposit
      CAI1ResponseStockSearch
      CAI1ResponseTypePackageGetText
      CAI1ResponseTypePackageInstall
      CAI1ResponseTypePackageSearch
      CAI1ResponseTypePackageUninstall
      CAI1ResponseTypePackageUpgrade
    ]
  ]
]
This section of the manual attempts to describe the security properties of the cardant server.
All command execution in the cardant server passes through a single code path that captures OpenTelemetry traces and publishes events. Administrators should write alerting rules in their metrics system of choice to watch for instances of the traces, metrics, and events described here; they almost certainly indicate malicious behaviour.
At the time of writing, events are published as part of a containing trace, and therefore the server must be configured to publish traces in order for an external monitoring system to be able to observe the events. The reason for this is that the OpenTelemetry Events API specification is not yet stable and so traces are currently the only way to publish events. It is expected that a stable version of the Events API will be released soon, and then the cardant server will switch to using that API directly (and this will require only log telemetry to be configured as opposed to full trace collection).
If an operation attempts to violate the server's built-in security policy, an exception will be raised with an cardant.errorCode attribute set to error-security-policy-denied.
An attacker with access to the APIs could send specially crafted messages designed to exhaust server resources during parsing/validation of the messages.
All APIs exposed by the idstore server are defined using the Cedarbridge protocol. Cedarbridge-based protocols have the following properties:

9.3.1.2.2. Cedarbridge Properties

  • Parsing and validation complexity is linear in the size of the parsed message. It is not possible to specify a message that will result in an exponentially complex parse.
  • Cedarbridge protocols are very strongly-typed, operate under a closed-world assumption, and are immune to any kind of reflection-based deserialization vulnerabilities. Deserialization of messages cannot under any circumstances result in the deserialization of arbitrary objects.
  • Cedarbridge protocols have a structure that is known ahead of time by both peers. Neither side gets to decide the structure of messages during communication. This is a common source of vulnerabilities in other protocols, where message types are self-describing on the wire and therefore a hostile client is able to transmit the description of a message that will cause the server to do an unbounded amount of work to parse and/or validate the message.
  • Parsing code generated by the Cedarbridge compiler does not preallocate any structures. It is not possible, therefore, for a specially-crafted message to result in the server performing a huge allocation based on an attacker-provided size value. If a message claims to provide a string that is 4294967295 octets long, the parser will attempt to consume 4294967295 octets one at a time. This requires an attacker to actually provide 4294967295 octets over the network, and the attacker will run into a hard request size limit before this completes.
Type packages are serialized using the following XML schema:

10.2. Type Package 1.0

<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:p="com.io7m.cardant:type_packages:1"
            targetNamespace="com.io7m.cardant:type_packages:1">

  <xsd:simpleType name="UnqualifiedNameType">
    <xsd:annotation>
      <xsd:documentation>
        The type of unqualified names.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="[a-z][a-z0-9_-]{0,62}"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="PackageNameType">
    <xsd:annotation>
      <xsd:documentation>
        The type of fully qualified package names.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="([a-z][a-z0-9_-]{0,63})(\.[a-z][a-z0-9_-]{0,62}){0,15}"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="PackageVersionType">
    <xsd:annotation>
      <xsd:documentation>
        The type of package versions.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:restriction base="xsd:string">
      <xsd:pattern value="([0-9]+)\.([0-9]+)\.([0-9]+)(-(.+))?"/>
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:element name="PackageInfo">
    <xsd:complexType>
      <xsd:attribute name="Name"
                     type="p:PackageNameType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The name of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="Version"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The version of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="Description"
                     type="xsd:string"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The description of the package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="VersionRange">
    <xsd:complexType>
      <xsd:attribute name="VersionLower"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The lower bound on the versions of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionLowerInclusive"
                     type="xsd:boolean"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The lower bound is inclusive.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionUpper"
                     type="p:PackageVersionType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The upper bound on the versions of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="VersionUpperInclusive"
                     type="xsd:boolean"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The upper bound is inclusive.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:element name="Import">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="p:VersionRange"/>
      </xsd:sequence>

      <xsd:attribute name="Package"
                     type="p:PackageNameType"
                     use="required">
        <xsd:annotation>
          <xsd:documentation>
            The name of the imported package.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:attribute>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="TypeDeclarationType"
                   abstract="true">
    <xsd:annotation>
      <xsd:documentation>
        The base type of type declarations.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:attribute name="Name"
                   type="p:UnqualifiedNameType"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The name of the type.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Description"
                   type="xsd:string"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The humanly-readable description of the type.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>

  <xsd:complexType name="TypeScalarType"
                   abstract="true">
    <xsd:complexContent>
      <xsd:extension base="p:TypeDeclarationType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar type.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:complexType name="TypeScalarTextType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar text type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="Pattern"
                       type="xsd:string"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The pattern that constrains text values.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarText"
               type="p:TypeScalarTextType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar text type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarIntegralType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar integral type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:long"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:long"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarIntegral"
               type="p:TypeScalarIntegralType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar integral type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarRealType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar real type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:double"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:double"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarReal"
               type="p:TypeScalarRealType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar real type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarTimeType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar time type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:dateTime"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:dateTime"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarTime"
               type="p:TypeScalarTimeType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar time type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeScalarMonetaryType">
    <xsd:complexContent>
      <xsd:extension base="p:TypeScalarType">
        <xsd:annotation>
          <xsd:documentation>
            A declaration of a scalar monetary type.
          </xsd:documentation>
        </xsd:annotation>

        <xsd:attribute name="RangeLower"
                       type="xsd:decimal"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The lower inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="RangeUpper"
                       type="xsd:decimal"
                       use="required">
          <xsd:annotation>
            <xsd:documentation>
              The upper inclusive bound.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="TypeScalarMonetary"
               type="p:TypeScalarMonetaryType">
    <xsd:annotation>
      <xsd:documentation>
        A declaration of a scalar monetary type.
      </xsd:documentation>
    </xsd:annotation>
  </xsd:element>

  <xsd:complexType name="TypeFieldType"
                   abstract="true">
    <xsd:attribute name="Name"
                   type="p:UnqualifiedNameType"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          The name of the record field.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Required"
                   type="xsd:boolean"
                   default="true">
      <xsd:annotation>
        <xsd:documentation>
          Whether the record field is required to be present.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>

    <xsd:attribute name="Description"
                   type="xsd:string"
                   use="required">
      <xsd:annotation>
        <xsd:documentation>
          A description of the record field.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>

  <xsd:complexType name="TypeFieldLocalType">
    <xsd:annotation>
      <xsd:documentation>
        A field that refers to a type within this package.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:complexContent>
      <xsd:extension base="p:TypeFieldType">
        <xsd:attribute name="Type"
                       use="required"
                       type="p:UnqualifiedNameType">
          <xsd:annotation>
            <xsd:documentation>
              The scalar type of the field.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="Field"
               type="p:TypeFieldLocalType"/>

  <xsd:complexType name="TypeFieldWithExternalTypeType">
    <xsd:annotation>
      <xsd:documentation>
        A field that refers to a type within another package.
      </xsd:documentation>
    </xsd:annotation>

    <xsd:complexContent>
      <xsd:extension base="p:TypeFieldType">
        <xsd:attribute name="Package"
                       use="required"
                       type="p:PackageNameType">
          <xsd:annotation>
            <xsd:documentation>
              The package containing the target type.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>

        <xsd:attribute name="Type"
                       use="required"
                       type="p:UnqualifiedNameType">
          <xsd:annotation>
            <xsd:documentation>
              The scalar type of the field.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:attribute>
      </xsd:extension>
    </xsd:complexContent>
  </xsd:complexType>

  <xsd:element name="FieldWithExternalType"
               type="p:TypeFieldWithExternalTypeType"/>

  <xsd:group name="TypeFieldGroup">
    <xsd:choice>
      <xsd:element ref="p:Field"/>
      <xsd:element ref="p:FieldWithExternalType"/>
    </xsd:choice>
  </xsd:group>

  <xsd:element name="TypeRecord">
    <xsd:complexType>
      <xsd:annotation>
        <xsd:documentation>
          A declaration of a record type.
        </xsd:documentation>
      </xsd:annotation>

      <xsd:complexContent>
        <xsd:extension base="p:TypeDeclarationType">
          <xsd:group ref="p:TypeFieldGroup"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
        </xsd:extension>
      </xsd:complexContent>
    </xsd:complexType>

    <xsd:unique name="TypeRecordFieldsUnique">
      <xsd:selector xpath="p:Field|p:FieldWithExternalType"/>
      <xsd:field xpath="@Name"/>
    </xsd:unique>
  </xsd:element>

  <xsd:group name="TypeDeclarationGroup">
    <xsd:choice>
      <xsd:element ref="p:TypeRecord"/>
      <xsd:element ref="p:TypeScalarIntegral"/>
      <xsd:element ref="p:TypeScalarMonetary"/>
      <xsd:element ref="p:TypeScalarReal"/>
      <xsd:element ref="p:TypeScalarText"/>
      <xsd:element ref="p:TypeScalarTime"/>
    </xsd:choice>
  </xsd:group>

  <xsd:element name="Package">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element ref="p:PackageInfo"/>
        <xsd:sequence minOccurs="0"
                      maxOccurs="unbounded">
          <xsd:element ref="p:Import"/>
        </xsd:sequence>
        <xsd:sequence minOccurs="0"
                      maxOccurs="unbounded">
          <xsd:group ref="p:TypeDeclarationGroup"/>
        </xsd:sequence>
      </xsd:sequence>
    </xsd:complexType>

    <xsd:key name="TypeScalarsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Scalar types must be uniquely named within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:TypeScalarIntegral|p:TypeScalarMonetary|p:TypeScalarReal|p:TypeScalarText|p:TypeScalarTime"/>
      <xsd:field xpath="@Name"/>
    </xsd:key>

    <xsd:key name="TypeRecordsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Record types must be uniquely named within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:TypeRecord"/>
      <xsd:field xpath="@Name"/>
    </xsd:key>

    <xsd:key name="ImportsUnique">
      <xsd:annotation>
        <xsd:documentation>
          Imports must be unique within a package.
        </xsd:documentation>
      </xsd:annotation>
      <xsd:selector xpath="p:Import"/>
      <xsd:field xpath="@Package"/>
    </xsd:key>
  </xsd:element>

</xsd:schema>
io7m | single-page | multi-page | epub | Cardant User Manual 1.0.0-beta0001