@@ -232,11 +232,11 @@ export function SCIMConfiguration(props: {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!scimConfiguration) {
|
if (hasIdentityProvider) {
|
||||||
if (hasIdentityProvider) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!scimConfiguration) {
|
||||||
return (
|
return (
|
||||||
<Card padded>
|
<Card padded>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|||||||
@@ -550,11 +550,15 @@ WHERE
|
|||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|
||||||
_, err = conn.Exec(ctx, q, args)
|
result, err := conn.Exec(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot update connector: %w", err)
|
return fmt.Errorf("cannot update connector: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result.RowsAffected() == 0 {
|
||||||
|
return ErrResourceNotFound
|
||||||
|
}
|
||||||
|
|
||||||
c.EncryptedConnection = encryptedConnection
|
c.EncryptedConnection = encryptedConnection
|
||||||
c.populateSlackSettings()
|
c.populateSlackSettings()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
-- Add sync tracking fields to iam_scim_bridges table
|
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN last_synced_at TIMESTAMP WITH TIME ZONE;
|
ALTER TABLE iam_scim_bridges ADD COLUMN last_synced_at TIMESTAMP WITH TIME ZONE;
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN next_sync_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
|
ALTER TABLE iam_scim_bridges ADD COLUMN next_sync_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN sync_error TEXT;
|
ALTER TABLE iam_scim_bridges ADD COLUMN sync_error TEXT;
|
||||||
|
|
||||||
-- Create index for efficient polling of bridges due for sync
|
|
||||||
CREATE INDEX idx_iam_scim_bridges_next_sync ON iam_scim_bridges (next_sync_at) WHERE state = 'ACTIVE';
|
CREATE INDEX idx_iam_scim_bridges_next_sync ON iam_scim_bridges (next_sync_at) WHERE state = 'ACTIVE';
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
-- Add failure tracking columns to iam_scim_bridges table
|
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN consecutive_failures INTEGER NOT NULL DEFAULT 0;
|
ALTER TABLE iam_scim_bridges ADD COLUMN consecutive_failures INTEGER NOT NULL DEFAULT 0;
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN total_sync_count INTEGER NOT NULL DEFAULT 0;
|
ALTER TABLE iam_scim_bridges ADD COLUMN total_sync_count INTEGER NOT NULL DEFAULT 0;
|
||||||
ALTER TABLE iam_scim_bridges ADD COLUMN total_failure_count INTEGER NOT NULL DEFAULT 0;
|
ALTER TABLE iam_scim_bridges ADD COLUMN total_failure_count INTEGER NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
-- Drop old index and create new one that covers all processable states
|
ALTER TABLE iam_scim_bridges ALTER COLUMN consecutive_failures DROP DEFAULT;
|
||||||
|
ALTER TABLE iam_scim_bridges ALTER COLUMN total_sync_count DROP DEFAULT;
|
||||||
|
ALTER TABLE iam_scim_bridges ALTER COLUMN total_failure_count DROP DEFAULT;
|
||||||
|
|
||||||
DROP INDEX IF EXISTS idx_iam_scim_bridges_next_sync;
|
DROP INDEX IF EXISTS idx_iam_scim_bridges_next_sync;
|
||||||
CREATE INDEX idx_iam_scim_bridges_next_sync ON iam_scim_bridges (next_sync_at) WHERE state IN ('ACTIVE', 'FAILED', 'SYNCING');
|
CREATE INDEX idx_iam_scim_bridges_next_sync ON iam_scim_bridges (next_sync_at) WHERE state IN ('ACTIVE', 'FAILED', 'SYNCING');
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ func (c *Client) DeactivateUser(ctx context.Context, userID string) error {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, _ := io.ReadAll(resp.Body)
|
||||||
return fmt.Errorf("SCIM API error: status %d, body: %s", resp.StatusCode, string(respBody))
|
return fmt.Errorf("SCIM API error: status %d, body: %s", resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,21 @@ func (r *BridgeRunner) calculateBackoff(consecutiveFailures int) time.Duration {
|
|||||||
return r.cfg.Interval
|
return r.cfg.Interval
|
||||||
}
|
}
|
||||||
|
|
||||||
backoff := r.cfg.Interval * time.Duration(1<<consecutiveFailures)
|
// Cap the shift exponent to prevent integer overflow from the shift itself.
|
||||||
|
// Bit 63 is the sign bit, so shifting by 63+ produces negative or zero values.
|
||||||
|
const maxShift = 62
|
||||||
|
shiftAmount := consecutiveFailures
|
||||||
|
if shiftAmount > maxShift {
|
||||||
|
shiftAmount = maxShift
|
||||||
|
}
|
||||||
|
|
||||||
|
backoff := r.cfg.Interval * time.Duration(1<<shiftAmount)
|
||||||
|
|
||||||
|
// Detect multiplication overflow: if result is non-positive or less than the
|
||||||
|
// base interval, overflow occurred. Return MaxBackoff in this case.
|
||||||
|
if backoff <= 0 || backoff < r.cfg.Interval {
|
||||||
|
return r.cfg.MaxBackoff
|
||||||
|
}
|
||||||
|
|
||||||
if backoff > r.cfg.MaxBackoff {
|
if backoff > r.cfg.MaxBackoff {
|
||||||
return r.cfg.MaxBackoff
|
return r.cfg.MaxBackoff
|
||||||
|
|||||||
Reference in New Issue
Block a user