Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions docs/advanced/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,73 @@ See: [Extensibility](extensibility.md).
IdLE treats workflow configuration and lifecycle requests as **untrusted data** and validates that they contain no ScriptBlocks.

Host-provided extension points (step registry, providers, external event sinks) are **trusted inputs** and are validated for safe shapes (object contracts). For details, see `advanced/security.md`.

## v1.0 Public API and Contracts

### Supported Commands

The **supported public API** for v1.0 consists of the following commands exported from the IdLE meta-module:

- `Test-IdleWorkflow`
- `New-IdleLifecycleRequest`
- `New-IdlePlan`
- `Invoke-IdlePlan`
- `Export-IdlePlan`
- `New-IdleAuthSession`

**Source of truth**: `src/IdLE/IdLE.psd1` → `FunctionsToExport`

Only these commands are considered **stable contracts**. Internal modules (IdLE.Core, IdLE.Steps.*, IdLE.Provider.*) are unsupported when imported directly.

### Command Contracts

For supported commands, the following are **stable contracts** (breaking changes require a major version):

- Command name
- Parameter names and parameter sets
- Observable semantics (mandatory/optional/default behavior)
- Output type identity at a coarse level (PSTypeName)

The following are **not contracts** and may change in minor/patch versions:

- Exact error message strings
- Undocumented internal object properties
- Internal module cmdlets

### Data Contracts

**Workflow authoring contract** (PSD1):
- Format: PSD1 workflow definitions validated by `Test-IdleWorkflow`
- Unknown keys: **FAIL** (strict validation)
- Required fields (Name, LifecycleEvent, Steps[].Name, Steps[].Type): **FAIL** if null/empty
- `With` payload values: allow `null` and empty strings (supports "clear attribute" scenarios)

**Lifecycle request contract**:
- Required fields: `LifecycleEvent`, `CorrelationId`
- Optional fields: `Actor`, `IdentityKeys`, `DesiredState`, `Changes`

**Plan export contract** (JSON):
- Format: JSON from `Export-IdlePlan`
- Schema and semantics are stable
- See [Plan export specification](../specs/plan-export.md)

### Capability ID Baseline (v1.0)

The following capability IDs are frozen as the v1.0 baseline:

- `IdLE.DirectorySync.Status` - Read directory sync status
- `IdLE.DirectorySync.Trigger` - Trigger directory sync
- `IdLE.Entitlement.Grant` - Grant group membership/entitlement
- `IdLE.Entitlement.List` - List user entitlements
- `IdLE.Entitlement.Revoke` - Revoke group membership/entitlement
- `IdLE.Identity.Attribute.Ensure` - Ensure identity attribute value
- `IdLE.Identity.Create` - Create identity
- `IdLE.Identity.Delete` - Delete identity
- `IdLE.Identity.Disable` - Disable identity
- `IdLE.Identity.Enable` - Enable identity
- `IdLE.Identity.Move` - Move identity (OU/container)
- `IdLE.Mailbox.Info.Read` - Read mailbox metadata/configuration
- `IdLE.Mailbox.OutOfOffice.Ensure` - Ensure Out of Office configuration
- `IdLE.Mailbox.Type.Ensure` - Ensure mailbox type (User/Shared/etc.)

**Deprecated (pre-1.0)**: `IdLE.Mailbox.Read` → automatically mapped to `IdLE.Mailbox.Info.Read` with deprecation warning during planning.
48 changes: 48 additions & 0 deletions docs/advanced/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,54 @@ These checks prevent "broken" releases (e.g., tagging the wrong commit or forget

## Versioning policy

IdLE follows [Semantic Versioning](https://semver.org/):

- **MAJOR** (breaking): Incompatible API changes
- **MINOR** (feature): Backward-compatible functionality additions
- **PATCH** (fix): Backward-compatible bug fixes

### What Constitutes a Breaking Change

The following are **breaking changes** and require a new major version:

- Removing a supported command
- Renaming a supported command
- Removing a parameter
- Renaming a parameter
- Changing a parameter from optional to mandatory
- Changing a parameter's type in an incompatible way
- Removing fields from workflow/request/plan contracts
- Renaming fields in workflow/request/plan contracts

The following are **non-breaking** (allowed in minor/patch versions):

- Adding a new command
- Adding a new parameter (must be optional with a sensible default)
- Changing exact error message strings
- Adding new output properties (output types are coarse-grained)
- Internal implementation changes

### Deprecation Mechanism

Deprecated supported cmdlets/parameters **MUST** emit a `Write-Warning` on use:

**Format**:
```
DEPRECATED: <Item> is deprecated in <version> and will be removed in <major_version>.
Use <replacement> instead.
```

**Example**:
```powershell
Write-Warning "DEPRECATED: Parameter 'OldName' is deprecated in v1.2 and will be removed in v2.0. Use 'NewName' instead."
```

**Timeline**: Deprecated features will be supported for **at least one minor version** before removal in the next major version.

**Example timeline**:
- Deprecated in v1.2 → Removed in v2.0
- Deprecated in v1.8 → Removed in v2.0

### Stable tags

Stable releases use tags in the form:
Expand Down
1 change: 1 addition & 0 deletions docs/reference/cmdlets.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This page links the generated per-cmdlet reference pages and includes their syno
| --- | --- |
| [Export-IdlePlan](cmdlets/Export-IdlePlan.md) | Exports an IdLE LifecyclePlan as a canonical JSON artifact. |
| [Invoke-IdlePlan](cmdlets/Invoke-IdlePlan.md) | Executes an IdLE plan. |
| [New-IdleAuthSession](cmdlets/New-IdleAuthSession.md) | Creates a simple AuthSessionBroker for use with IdLE providers. |
| [New-IdleLifecycleRequest](cmdlets/New-IdleLifecycleRequest.md) | Creates a lifecycle request object. |
| [New-IdlePlan](cmdlets/New-IdlePlan.md) | Creates a deterministic plan from a lifecycle request and a workflow definition. |
| [Test-IdleWorkflow](cmdlets/Test-IdleWorkflow.md) | Validates an IdLE workflow definition file. |
94 changes: 94 additions & 0 deletions docs/reference/cmdlets/New-IdleAuthSession.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
external help file: IdLE-help.xml
Module Name: IdLE
online version:
schema: 2.0.0
---

# New-IdleAuthSession

## SYNOPSIS
Creates a simple AuthSessionBroker for use with IdLE providers.

## SYNTAX

```
New-IdleAuthSession [-SessionMap] <Hashtable> [[-DefaultCredential] <PSCredential>]
[-ProgressAction <ActionPreference>] [<CommonParameters>]
```

## DESCRIPTION
Creates an AuthSessionBroker that routes authentication based on user-defined options.
The broker is used by steps to acquire credentials at runtime without embedding
secrets in workflows or provider construction.

This is a thin wrapper that delegates to IdLE.Core\New-IdleAuthSessionBroker.

## EXAMPLES

### EXAMPLE 1
```
$broker = New-IdleAuthSession -SessionMap @{
@{ Role = 'Tier0' } = $tier0Credential
}
```

## PARAMETERS

### -SessionMap
A hashtable that maps session configurations to credentials.

```yaml
Type: Hashtable
Parameter Sets: (All)
Aliases:

Required: True
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -DefaultCredential
Optional default credential to return when no session options are provided.

```yaml
Type: PSCredential
Parameter Sets: (All)
Aliases:

Required: False
Position: 2
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -ProgressAction
{{ Fill ProgressAction Description }}

```yaml
Type: ActionPreference
Parameter Sets: (All)
Aliases: proga

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).

## INPUTS

## OUTPUTS

### PSCustomObject with AcquireAuthSession method
## NOTES
For detailed documentation, see: Get-Help IdLE.Core\New-IdleAuthSessionBroker -Full

## RELATED LINKS
8 changes: 4 additions & 4 deletions docs/reference/providers/provider-ad.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ $plan = New-IdlePlan -WorkflowPath './workflow.psd1' -Request $request -Provider

Use an AuthSessionBroker to manage authentication centrally and enable multi-role scenarios.

**Simple approach with New-IdleAuthSessionBroker:**
**Simple approach with New-IdleAuthSession:**

```powershell
# Assuming you have credentials available (e.g., from a secure vault or credential manager)
Expand All @@ -112,7 +112,7 @@ $adminCredential = Get-Credential -Message "Enter regular admin credentials"
$provider = New-IdleADIdentityProvider

# Create broker with role-based credential mapping
$broker = New-IdleAuthSessionBroker -SessionMap @{
$broker = New-IdleAuthSession -SessionMap @{
@{ Role = 'Tier0' } = $tier0Credential
@{ Role = 'Admin' } = $adminCredential
} -DefaultCredential $adminCredential
Expand Down Expand Up @@ -195,8 +195,8 @@ $targetCred = Get-Credential -Message "Enter Target AD admin credentials"
$sourceAD = New-IdleADIdentityProvider
$targetAD = New-IdleADIdentityProvider -AllowDelete

# Use New-IdleAuthSessionBroker for domain-based credential routing
$broker = New-IdleAuthSessionBroker -SessionMap @{
# Use New-IdleAuthSession for domain-based credential routing
$broker = New-IdleAuthSession -SessionMap @{
@{ Domain = 'Source' } = $sourceCred
@{ Domain = 'Target' } = $targetCred
}
Expand Down
6 changes: 3 additions & 3 deletions docs/reference/providers/provider-entraID.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Connect-AzAccount
$token = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

# Create broker
$broker = New-IdleAuthSessionBroker -SessionMap @{
$broker = New-IdleAuthSession -SessionMap @{
@{} = $token
} -DefaultCredential $token

Expand All @@ -71,7 +71,7 @@ $tenantId = "your-tenant-id"
$token = Get-GraphAppOnlyToken -ClientId $clientId -ClientSecret $clientSecret -TenantId $tenantId

# Create broker
$broker = New-IdleAuthSessionBroker -SessionMap @{
$broker = New-IdleAuthSession -SessionMap @{
@{} = $token
} -DefaultCredential $token

Expand All @@ -84,7 +84,7 @@ $broker = New-IdleAuthSessionBroker -SessionMap @{
$tier0Token = Get-GraphToken -Role 'Tier0'
$adminToken = Get-GraphToken -Role 'Admin'

$broker = New-IdleAuthSessionBroker -SessionMap @{
$broker = New-IdleAuthSession -SessionMap @{
@{ Role = 'Tier0' } = $tier0Token
@{ Role = 'Admin' } = $adminToken
} -DefaultCredential $adminToken
Expand Down
7 changes: 7 additions & 0 deletions src/IdLE.Core/IdLE.Core.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

Set-StrictMode -Version Latest

# Internal module warning: discourage direct import unless explicitly allowed
# Suppress warning if IDLE_ALLOW_INTERNAL_IMPORT is set
# (IdLE meta-module sets this automatically; users can also set it for advanced scenarios)
if (-not $env:IDLE_ALLOW_INTERNAL_IMPORT) {
Write-Warning "IdLE.Core is an internal/unsupported module. Import 'IdLE' instead for the supported public API. To bypass: `$env:IDLE_ALLOW_INTERNAL_IMPORT = '1'"
}

$PublicPath = Join-Path -Path $PSScriptRoot -ChildPath 'Public'
$PrivatePath = Join-Path -Path $PSScriptRoot -ChildPath 'Private'

Expand Down
55 changes: 53 additions & 2 deletions src/IdLE.Core/Public/New-IdlePlanObject.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ function New-IdlePlanObject {
)
}

$normalized += $s
# Normalize deprecated capabilities
$normalized += ConvertTo-IdleNormalizedCapability -Capability $s
}

return @($normalized | Sort-Object -Unique)
Expand Down Expand Up @@ -217,6 +218,45 @@ function New-IdlePlanObject {
return @($Providers)
}

function ConvertTo-IdleNormalizedCapability {
<#
.SYNOPSIS
Normalizes capability identifiers and maps deprecated IDs to current ones.

.DESCRIPTION
Handles capability ID migrations and deprecation warnings during planning.
Pre-1.0 deprecated capability IDs are mapped to their replacements and emit a warning.

.PARAMETER Capability
The raw capability identifier to normalize.

.OUTPUTS
Normalized capability identifier (string).
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string] $Capability
)

# Deprecated capability ID mappings (pre-1.0)
# Format: @{ 'OldID' = 'NewID' }
$deprecatedMappings = @{
'IdLE.Mailbox.Read' = 'IdLE.Mailbox.Info.Read'
}

$normalized = $Capability.Trim()

if ($deprecatedMappings.ContainsKey($normalized)) {
$newId = $deprecatedMappings[$normalized]
Write-Warning "DEPRECATED: Capability '$normalized' is deprecated in v1.0 and will be removed in v2.0. Use '$newId' instead."
return $newId
}

return $normalized
}

function Get-IdleProviderCapabilities {
<#
.SYNOPSIS
Expand All @@ -242,7 +282,18 @@ function New-IdlePlanObject {
if ($null -eq $caps) {
return @()
}
return @($caps | Where-Object { $null -ne $_ } | ForEach-Object { ([string]$_).Trim() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Sort-Object -Unique)
return @(
$caps |
Where-Object { $null -ne $_ } |
ForEach-Object {
$rawCap = ([string]$_).Trim()
if (-not [string]::IsNullOrWhiteSpace($rawCap)) {
ConvertTo-IdleNormalizedCapability -Capability $rawCap
}
} |
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
Sort-Object -Unique
)
}

return @()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function New-IdleExchangeOnlineProvider {

$provider | Add-Member -MemberType ScriptMethod -Name GetCapabilities -Value {
$caps = @(
'IdLE.Mailbox.Read'
'IdLE.Mailbox.Info.Read'
'IdLE.Mailbox.Type.Ensure'
'IdLE.Mailbox.OutOfOffice.Ensure'
)
Expand Down
Loading