Posix Provider
This document describes the implementation details of the Posix file provider for managing files and directories on Unix-like systems.
Provider Selection
The Posix provider is the default and only file provider. It is always available and returns priority 1 for all file resources.
Operations
Store (Create/Update File)
Process:
- Verify parent directory exists
- Parse file mode from octal string
- Open source file if
sourceproperty is set - Create temporary file in the same directory as target
- Set file permissions on temp file
- Write content (from
sourcefile orcontentsproperty) - Set ownership (chown) on temp file
- Close temp file
- Atomic rename temp file to target path
Atomic Write Pattern:
The temp file is created in the same directory as the target to ensure os.Rename() is atomic (same filesystem).
Content Sources:
| Property | Behavior |
|---|---|
contents | Write string directly to file (template-resolved) |
source | Copy from local file path (adjusted for working directory) |
If both are empty, an empty file is created.
Error Handling:
| Condition | Behavior |
|---|---|
| Parent directory doesn’t exist | Return error: “is not a directory” |
| Invalid mode format | Return error from strconv.ParseUint |
| Source file not found | Return error from os.Open |
| Permission denied | Return error from underlying syscall |
| Rename failure | Return error: “could not rename temporary file” |
CreateDirectory
Process:
- Parse file mode from octal string
- Create directory and parents via
os.MkdirAll() - Lookup numeric UID/GID from owner/group names
- Set permissions via
os.Chmod()(ensures correct mode even if umask affected MkdirAll) - Set ownership via
os.Chown()
Command Sequence:
The explicit Chmod after MkdirAll is necessary because MkdirAll applies the process umask to the mode.
Status
Process:
- Initialize state with default metadata
- Call
os.Stat()on file path - Based on result, populate state accordingly
State Detection:
os.Stat() Result | Ensure Value | Metadata |
|---|---|---|
| File exists | present | Size, mtime, owner, group, mode, checksum |
| Directory exists | directory | Size, mtime, owner, group, mode |
os.ErrNotExist | absent | None |
os.ErrPermission | absent | None (logged as warning) |
| Other error | (unchanged) | None (logged as warning) |
Metadata Collection:
| Field | Source |
|---|---|
Name | From properties |
Provider | “posix” |
Size | FileInfo.Size() |
MTime | FileInfo.ModTime() |
Owner | util.GetFileOwner() - resolves UID to username |
Group | util.GetFileOwner() - resolves GID to group name |
Mode | util.GetFileOwner() - octal string (e.g., “0644”) |
Checksum | util.Sha256HashFile() - SHA256 hash (files only) |
Note: Checksum is only calculated for regular files, not directories.
Idempotency
The file resource achieves idempotency by comparing current state against desired state:
State Checks
The isDesiredState() function checks (in order):
- Ensure value matches -
present,absent, ordirectory - Content checksum matches - SHA256 of contents vs existing file (for files only)
- Owner matches - Username comparison
- Group matches - Group name comparison
- Mode matches - Octal permission string comparison
Decision Flow
Content Comparison
For files with ensure: present:
| Content Source | Checksum Calculation |
|---|---|
contents property | Sha256HashBytes([]byte(contents)) |
source property | Sha256HashFile(adjustedSourcePath) |
The source path is adjusted based on the manager’s working directory when set.
Mode Validation
File modes are validated during resource creation:
- Strip optional
0oor0Oprefix - Parse as octal number (base 8)
- Validate range: must be β€
0777
Valid Mode Examples:
| Input | Parsed Value |
|---|---|
"0644" | 0o644 |
"644" | 0o644 |
"0o755" | 0o755 |
"0O700" | 0o700 |
Invalid Mode Examples:
| Input | Error |
|---|---|
"0888" | Invalid octal digit |
"1777" | Exceeds maximum (setuid/setgid not supported via mode) |
"rw-r--r--" | Not octal format |
Ownership Resolution
Owner and group names are resolved to numeric UID/GID via:
This uses the system’s user database (/etc/passwd, /etc/group, or equivalent):
user.Lookup(owner)β UIDuser.LookupGroup(group)β GID
Error Handling:
| Condition | Behavior |
|---|---|
| User not found | Return error: “could not lookup user” |
| Group not found | Return error: “could not lookup group” |
| Invalid UID/GID format | Return error from strconv.Atoi |
Working Directory Support
When a manager has a working directory set (e.g., from extracted manifest), the source property path is adjusted:
This allows manifests to use relative paths for source files bundled with the manifest.
Platform Support
The Posix provider uses Unix-specific system calls:
| Operation | System Call |
|---|---|
| Get file owner/group | syscall.Stat_t (UID/GID from stat) |
| Set ownership | os.Chown() β chown(2) |
| Set permissions | os.Chmod() β chmod(2) |
The provider has separate implementations for Unix and Windows (file_unix.go, file_windows.go in internal/util), with Windows returning errors for ownership operations.
Security Considerations
Atomic Writes
Files are written atomically via temp file + rename. This prevents:
- Partial file reads during write
- Corruption if process is interrupted
- Race conditions with concurrent readers
Permission Ordering
Permissions and ownership are set on the temp file before rename:
Chmod- Set permissions- Write content
Chown- Set ownership- Rename to target
This ensures the file never exists at the target path with incorrect permissions.
Path Validation
File paths must be absolute and clean (no . or .. components):
Required Properties
Owner, group, and mode are required properties and cannot be empty, preventing accidental creation of files with default/inherited permissions.