dog-and-duck.quack.picky

Fault-finder for ActivityPub documents.

Generally, each -faults function will return:

  1. nil if no faults were found;
  2. a sequence of fault objects if faults were found.

Each fault object shall have the properties:

  1. :@context whose value shall be the URL of a document specifying this vocabulary;
  2. :type whose value shall be Fault;
  3. :severity whose value shall be one of info, minor, should, must or critical;
  4. :fault whose value shall be a unique token representing the particular fault type;
  5. :narrative whose value shall be a natural language description of the fault type.

Note that the reason for the :fault property is to be able to have a well known place, linked to from the @context URL, which allows narratives for each fault type to be served in as many natural languages as possible.

The idea further is that it should ultimately be possible to serialise a fault report as a document which in its own right conforms to the ActivityStreams spec.

*reify-refs*

dynamic

If true, references to objects in fields will be reified and validated. If false, they won’t, but an :info level fault report will be generated.

There are several things in the spec which, in a document, may correctly be either

  1. a fully fleshed out object, or
  2. a URI pointing to such an object.

Obviously to fully validate a document we ought to reify all the refs and check that they are themselves valid, but

a. in some of the published test documents the URIs do not reference a valid document; b. there will be performance costs to reifying all the refs; c. in perverse cases, reifying refs might result in runaway recursion.

TODO: I think that in production this should default to true.

*reject-severity*

dynamic

The severity at which the binary validator will return false.

In practice documents seen in the wild do not typically appear to be fully valid, and this does not matter. This allows the sensitivity of the binary validator (dog-and-duck.quack.quack) to be tuned. It’s in this (dog-and-duck.quack.picky) namespace, not that one, because this namespace is where concerns about severity are handled.

accept-required-properties

As base-activity-required-properties, except that the type of the object is restricted.

activity-faults

(activity-faults x)

TODO: write docs

activity-required-properties

Properties activities should have, keyed by activity type. Values are maps of the format of base-activity-required-properties, q.v.

activity-type-faults

(activity-type-faults x)(activity-type-faults x type)

Return a list of faults found in the activity x; if type is also specified, it should be a string naming a specific activity type for which checks should be performed.

Some specific activity types have specific requirements which are not requirements.

activitystreams-context-uri

The URI of the context of an ActivityStreams object is expected to be this literal string.

actor-faults

(actor-faults x)

Return a list of faults found in actor x, or nil if none are.

actor-type?

(actor-type? x)

Return true if the x is a recognised actor type, else false.

actor-types

The set of types we will accept as actors.

There’s an explicit set of allowed actor types.

base-activity-required-properties

Properties most activities should have. Values are validating functions, each.

See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-activity

coll-object-reference-or-fault

(coll-object-reference-or-fault value expected-type severity token)

As object-reference-or-fault, except value argument may also be a list of objects and/or object references.

context-key

The Clojure reader barfs on :@context, although it is in principle a valid keyword. So we’ll make it once, here, to make the code more performant and easier to read.

context?

(context? x)

Returns true iff x quacks like an ActivityStreams context, else false.

A context is either 1. the URI (actually an IRI) activitystreams-context-uri, or 2. a collection comprising that URI and a map.

filter-severity

(filter-severity reports severity)

Return a list of reports taken from these reports where the severity of the report is greater than this or equal to this severity.

has-activity-type?

(has-activity-type? x)

Return true if the object x has a type which is an activity type, else false.

has-actor-type?

(has-actor-type? x)

Return true if the object x has a type which is an actor type, else false.

has-context?

macro

(has-context? x)

True if x is an ActivityStreams object with a valid context, else false.

has-type-or-fault

(has-type-or-fault x acceptable severity token)

If object x has a :type value which is acceptable, return nil; else return a fault object with this severity and token.

acceptable may be passed as either nil, a string, or a set of strings. If acceptable is nil, no type specific tests will be performed.

has-type?

(has-type? x type)

Return true if object x has type type, else false.

The values of type fields of ActivityStreams objects may be lists; they are considered to have a type if the type token is a member of the list.

intransitive-activity-required-properties

Properties intransitive activities should have.

See https://www.w3.org/TR/activitystreams-vocabulary/#dfn-intransitiveactivity

make-fault-object

(make-fault-object severity fault)

Return a fault object with these severity, fault and narrative values.

An ActivityPub object MUST have a globally unique ID. Whether this is meaningful depends on whether we persist fault report objects and serve them, which at present I have no plans to do.

nil-if-empty

macro

(nil-if-empty x)

if x is an empty collection, return nil; else return x.

object-faults

(object-faults x)(object-faults x expected-type)

Return a list of faults found in object x, or nil if none are.

If expected-type is also passed, verify that x has expected-type. expected-type may be passed as a string or as a set of strings.

object-reference-or-faults

(object-reference-or-faults value expected-type severity token)

If this value is either

  1. an object of expected-type;
  2. a URI referencing an object of expected-type; or
  3. a link object referencing an object of expected-type

and no faults are returned from validating the linked object, then return nil; else return a sequence comprising a fault object with this severity and token, prepended to the faults returned.

As with has-type-or-fault (q.v.), expected-type may be passed as a string or as a set of strings.

NOTE THAT if *reify-refs* is false, referenced objects will not actually be checked.

persistent-object-faults

(persistent-object-faults x)

Return a list of faults found in persistent object x, or nil if none are.

severity

Severity of faults found, as follows:

  1. :info not actually a fault, but an issue noted during validation;
  2. :minor things which I consider to be faults, but which don’t actually breach the spec;
  3. :should instances where the spec says something SHOULD be done, which isn’t;
  4. :must instances where the spec says something MUST be done, which isn’t;
  5. :critical instances where I believe the fault means that the object cannot be meaningfully processed.

severity-filters

Hack for implementing a severity hierarchy

string-or-fault

(string-or-fault value severity token)(string-or-fault value severity token pattern)

If this value is not a string, return a fault object with this severity and token, else nil. If pattern is also passed, it is expected to be a Regex, and the fault object will be returned unless value matches the pattern.

truthy?

(truthy? x)

Return true if x is truthy, else false.

uri-or-fault

(uri-or-fault u severity if-missing-token)(uri-or-fault u severity if-missing-token if-invalid-token)

If u is not a valid URI, return a fault object with this severity and if-invalid-token. If it’s nil, return a fault object with this severity and if-missing-token. Otherwise return nil.

validation-fault-context-uri

The URI of the context of a validation fault report object shall be this literal string.

verb-type?

(verb-type? x)

true if x, a string, represents a recognised ActivityStreams activity type.

verb-types

The set of types we will accept as verbs.

There’s an explicit set of allowed verb types.