Appearance
Configuration
Everything the module reads is in one section, GrydFiles, plus the engine's address in GrydClamAv. The reasons behind each value are in ADR 0010; the authoritative table of profile fields is §14 of the specification.
Nothing about the storage provider lives here. Bucket, region, credentials and DefaultPrefix stay in GrydStorage, which AddGrydObjectStorage already owns; the module reaches the object through IObjectStorageService and records the effective provider and bucket on each file.
The section
json
{
"GrydFiles": {
"PurgeGracePeriodDays": 30,
"QuarantineRetentionDays": 365,
"ScanQueueAlertThreshold": 100,
"ScanQueueAlertMaxAge": "00:30:00",
"Scanner": {
"TimeoutSeconds": 120,
"RetryDelays": [ "00:01:00", "00:05:00", "00:15:00" ],
"StreamMaxLengthBytes": 67108864,
"MaxFileSizeBytes": 67108864,
"MaxScanSizeBytes": 419430400,
"MaxRecursion": 16,
"MaxFiles": 10000,
"ConcurrentDatabaseReload": true,
"AlertOnExceededLimits": true,
"UseIdSession": false
},
"Profiles": {
"gryd.report": {
"MaxSizeBytes": 52428800,
"AllowedContentTypes": [ "application/pdf", "text/csv", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ],
"ScanRequired": false,
"DefaultRetentionMode": "UntilReleased"
},
"gryd.notification-attachment": {
"MaxSizeBytes": 10485760,
"AllowedContentTypes": [ "application/pdf", "image/png", "image/jpeg", "text/csv" ],
"ScanRequired": true,
"DefaultRetentionMode": "RetainUntil",
"DefaultRetentionDays": 30
}
}
},
"GrydClamAv": {
"Host": "clamd",
"Port": 3310
}
}Module-wide settings
| Key | Default | Meaning |
|---|---|---|
PurgeGracePeriodDays | 30 | How long an UntilReleased file survives after its last reference is released — or after its verdict, if nobody ever referenced it — before the retention job purges it |
QuarantineRetentionDays | 365 | How long infected content stays under _quarantine/ as evidence. Global, never per profile (D9): an infected file is not more or less evidence depending on how it was uploaded |
ScanQueueAlertThreshold | 100 | Files waiting for a verdict above which the queue alert fires |
ScanQueueAlertMaxAge | 00:30:00 | Age of the oldest waiting file above which the queue alert fires. Above the retry budget, so a file that is only retrying does not trip it |
Scanner — the antivirus limits
clamd.conf is generated from this section, never written by hand (D15). The same numbers the application validates the profiles against are the numbers the daemon runs with, and an incoherent section — a profile ceiling above StreamMaxLengthBytes, a MaxScanSizeBytes below MaxFileSizeBytes — fails the start-up; it is not a warning in a log.
| Key | Default | Meaning |
|---|---|---|
TimeoutSeconds | 120 | How long one pass may take before it counts as a Timeout (D14). Client-side; not a clamd directive |
RetryDelays | 1, 5 and 15 min | The waits between passes after an infrastructure failure: the first pass and three more (D14). Client-side |
StreamMaxLengthBytes | 67108864 (64M) | StreamMaxLength — the largest stream INSTREAM accepts. Must be above the largest profile ceiling |
MaxFileSizeBytes | 67108864 (64M) | MaxFileSize |
MaxScanSizeBytes | 419430400 (400M) | MaxScanSize — how much the engine reads out of an archive |
MaxRecursion | 16 | MaxRecursion — nesting depth of archives |
MaxFiles | 10000 | MaxFiles — members read out of one archive |
ConcurrentDatabaseReload | true | Keeps scanning while the signature database reloads, at the cost of two copies in memory |
AlertOnExceededLimits | true | AlertExceedsMax. Off, a file that exceeds a limit comes back stream: OK unread; on, it is a failure, never a release |
UseIdSession | false | Reuses one connection for several scans. Client-side |
Why 64M and not clamd's default of 25M (D13): 25M is exactly the largest profile in use (26 214 400 bytes), which leaves no room for the INSTREAM framing. Every parameter, its rendering and its rationale are on clamd.conf.
Profiles — a profile is configuration, not a table
Each profile is an entry of the dictionary, named in every upload. There is no default profile (D12): a name nobody configured is FILE_PROFILE_UNKNOWN. The framework declares only gryd.report and gryd.notification-attachment; a product adds its own (nexio.attachment, nexio.import, …) in its own appsettings.
| Field | Default | Meaning |
|---|---|---|
MaxSizeBytes | — (required) | The ceiling, checked at the reservation, before any URL is issued (FILE_TOO_LARGE_UNPROCESSABLE). RN-GF-11: no profile without one |
AllowedContentTypes | — (required) | An allow list, never a deny list. The declared type is checked at the reservation; the real one, by content, after the upload |
ScanRequired | true | false waives the antivirus only. The content-type check and the server-side sha256 still run (D7), and the waiver is written to the audit trail at start-up |
UploadUrlTtlMinutes | 15 | Validity of the upload URL, and the deadline of the confirmation (FILE_UPLOAD_EXPIRED_CONFLICT) |
DownloadUrlTtlMinutes | 5 | Validity of each download URL |
DefaultRetentionMode | — (required) | UntilReleased, RetainUntil or Permanent, inherited by an upload that declares none |
DefaultRetentionDays | — | Required with RetainUntil: the module computes retainUntil from it |
Who computes retainUntil
It depends on where the mode came from:
- Declared in the upload as
RetainUntil: the consumer sends the date. The module only checks that it is in the future. - Inherited from the profile: the module computes it from
DefaultRetentionDays, counted from the reservation. Without that, every consumer of a 90-day profile would do the arithmetic itself.
Either way, the date only moves forward afterwards (RN-GF-09): PUT /files/{id}/retention with an earlier date is FILE_RETENTION_SHORTENED_UNPROCESSABLE. See Retention & Purge.
GrydClamAv — where the engine is
| Key | Default | Meaning |
|---|---|---|
Host | localhost | The clamd service — an address, never a replica |
Port | 3310 | Its TCP port |
ChunkSizeBytes | adapter default | Size of each INSTREAM chunk |
The connection string
Resolved from ConnectionStrings:GrydFiles, then DefaultConnection, then DefaultPostgresConnection — the chain the other modules use. AddGrydFiles also accepts a configureDbContext callback when the host wants to configure the provider itself.