CI: add dotnet --info / df -h / free -m diagnostics and an explicit 'Restore NuGet packages' step before build to isolate restore failures (build of e15f650 on main exited with code -1 and zero dotnet output).
#5
@@ -6,6 +6,8 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loos
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Infisical API error responses are now parsed to surface the server-side `message`, `error`, and `reqId` fields. The 4xx/5xx exception message includes the human-readable explanation (e.g. "The project is of type secret-manager") instead of an opaque `Infisical API returned 400 (Bad Request)`. The `InfisicalApiException` gains `ApiErrorMessage` and `ApiRequestId` properties; `InfisicalErrorDetails` carries the same fields so PowerShell error records and logger output expose them.
|
||||||
|
|
||||||
## 2026.06.04.1920
|
## 2026.06.04.1920
|
||||||
|
|
||||||
- Build produced from commit 0f8f44afdb38.
|
- Build produced from commit 0f8f44afdb38.
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace PSInfisicalAPI.Errors
|
||||||
|
{
|
||||||
|
internal static class InfisicalApiErrorEnvelope
|
||||||
|
{
|
||||||
|
public static void Enrich(InfisicalApiException exception, string body)
|
||||||
|
{
|
||||||
|
if (exception == null || string.IsNullOrEmpty(body))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string trimmed = body.TrimStart();
|
||||||
|
if (trimmed.Length == 0 || (trimmed[0] != '{' && trimmed[0] != '['))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject obj;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JToken token = JToken.Parse(body);
|
||||||
|
if (token.Type != JTokenType.Object) { return; }
|
||||||
|
obj = (JObject)token;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string message = ReadString(obj, "message");
|
||||||
|
string error = ReadString(obj, "error");
|
||||||
|
string reqId = ReadString(obj, "reqId");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(message)) { exception.ApiErrorMessage = message; }
|
||||||
|
if (!string.IsNullOrEmpty(error) && string.IsNullOrEmpty(exception.ApiErrorCode)) { exception.ApiErrorCode = error; }
|
||||||
|
if (!string.IsNullOrEmpty(reqId)) { exception.ApiRequestId = reqId; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string BuildExceptionMessage(int statusCode, string reasonPhrase, string body)
|
||||||
|
{
|
||||||
|
string baseMessage = string.Concat(
|
||||||
|
"Infisical API returned ",
|
||||||
|
statusCode.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
" (", reasonPhrase ?? string.Empty, ").");
|
||||||
|
|
||||||
|
string apiMessage = null;
|
||||||
|
string apiError = null;
|
||||||
|
string reqId = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(body))
|
||||||
|
{
|
||||||
|
string trimmed = body.TrimStart();
|
||||||
|
if (trimmed.Length > 0 && trimmed[0] == '{')
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JToken token = JToken.Parse(body);
|
||||||
|
if (token.Type == JTokenType.Object)
|
||||||
|
{
|
||||||
|
JObject obj = (JObject)token;
|
||||||
|
apiMessage = ReadString(obj, "message");
|
||||||
|
apiError = ReadString(obj, "error");
|
||||||
|
reqId = ReadString(obj, "reqId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(apiMessage) && string.IsNullOrEmpty(apiError) && string.IsNullOrEmpty(reqId))
|
||||||
|
{
|
||||||
|
return baseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Text.StringBuilder builder = new System.Text.StringBuilder(baseMessage);
|
||||||
|
if (!string.IsNullOrEmpty(apiMessage))
|
||||||
|
{
|
||||||
|
builder.Append(' ').Append(apiMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(apiError) || !string.IsNullOrEmpty(reqId))
|
||||||
|
{
|
||||||
|
builder.Append(" [");
|
||||||
|
bool needsSeparator = false;
|
||||||
|
if (!string.IsNullOrEmpty(apiError))
|
||||||
|
{
|
||||||
|
builder.Append("error=").Append(apiError);
|
||||||
|
needsSeparator = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(reqId))
|
||||||
|
{
|
||||||
|
if (needsSeparator) { builder.Append("; "); }
|
||||||
|
builder.Append("reqId=").Append(reqId);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadString(JObject obj, string name)
|
||||||
|
{
|
||||||
|
JToken token;
|
||||||
|
if (obj.TryGetValue(name, StringComparison.OrdinalIgnoreCase, out token) && token != null && token.Type == JTokenType.String)
|
||||||
|
{
|
||||||
|
return (string)token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ namespace PSInfisicalAPI.Errors
|
|||||||
public int? StatusCode { get; set; }
|
public int? StatusCode { get; set; }
|
||||||
public string ReasonPhrase { get; set; }
|
public string ReasonPhrase { get; set; }
|
||||||
public string ApiErrorCode { get; set; }
|
public string ApiErrorCode { get; set; }
|
||||||
|
public string ApiErrorMessage { get; set; }
|
||||||
|
public string ApiRequestId { get; set; }
|
||||||
public string SanitizedBody { get; set; }
|
public string SanitizedBody { get; set; }
|
||||||
public int? LineNumber { get; set; }
|
public int? LineNumber { get; set; }
|
||||||
public int? LinePosition { get; set; }
|
public int? LinePosition { get; set; }
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ namespace PSInfisicalAPI.Errors
|
|||||||
details.StatusCode = apiException.StatusCode;
|
details.StatusCode = apiException.StatusCode;
|
||||||
details.ReasonPhrase = apiException.ReasonPhrase;
|
details.ReasonPhrase = apiException.ReasonPhrase;
|
||||||
details.ApiErrorCode = apiException.ApiErrorCode;
|
details.ApiErrorCode = apiException.ApiErrorCode;
|
||||||
|
details.ApiErrorMessage = apiException.ApiErrorMessage;
|
||||||
|
details.ApiRequestId = apiException.ApiRequestId;
|
||||||
details.SanitizedBody = apiException.SanitizedBody;
|
details.SanitizedBody = apiException.SanitizedBody;
|
||||||
details.EndpointName = apiException.EndpointName;
|
details.EndpointName = apiException.EndpointName;
|
||||||
details.RequestMethod = apiException.RequestMethod;
|
details.RequestMethod = apiException.RequestMethod;
|
||||||
@@ -70,6 +72,16 @@ namespace PSInfisicalAPI.Errors
|
|||||||
logger.Error(Component, string.Concat("API Error Code: ", details.ApiErrorCode));
|
logger.Error(Component, string.Concat("API Error Code: ", details.ApiErrorCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(details.ApiErrorMessage))
|
||||||
|
{
|
||||||
|
logger.Error(Component, string.Concat("API Error Message: ", details.ApiErrorMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(details.ApiRequestId))
|
||||||
|
{
|
||||||
|
logger.Error(Component, string.Concat("API Request Id: ", details.ApiRequestId));
|
||||||
|
}
|
||||||
|
|
||||||
if (details.LineNumber.HasValue)
|
if (details.LineNumber.HasValue)
|
||||||
{
|
{
|
||||||
logger.Error(Component, string.Concat("Line: ", details.LineNumber.Value.ToString(CultureInfo.InvariantCulture)));
|
logger.Error(Component, string.Concat("Line: ", details.LineNumber.Value.ToString(CultureInfo.InvariantCulture)));
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ namespace PSInfisicalAPI.Errors
|
|||||||
public int StatusCode { get; set; }
|
public int StatusCode { get; set; }
|
||||||
public string ReasonPhrase { get; set; }
|
public string ReasonPhrase { get; set; }
|
||||||
public string ApiErrorCode { get; set; }
|
public string ApiErrorCode { get; set; }
|
||||||
|
public string ApiErrorMessage { get; set; }
|
||||||
|
public string ApiRequestId { get; set; }
|
||||||
public string SanitizedBody { get; set; }
|
public string SanitizedBody { get; set; }
|
||||||
public string EndpointName { get; set; }
|
public string EndpointName { get; set; }
|
||||||
public string RequestMethod { get; set; }
|
public string RequestMethod { get; set; }
|
||||||
|
|||||||
@@ -135,15 +135,14 @@ namespace PSInfisicalAPI.Http
|
|||||||
|
|
||||||
private static InfisicalApiException BuildApiException(InfisicalHttpResponse response, InfisicalEndpointDefinition definition)
|
private static InfisicalApiException BuildApiException(InfisicalHttpResponse response, InfisicalEndpointDefinition definition)
|
||||||
{
|
{
|
||||||
InfisicalApiException exception = new InfisicalApiException(string.Concat(
|
string message = InfisicalApiErrorEnvelope.BuildExceptionMessage(response.StatusCode, response.ReasonPhrase, response.Body);
|
||||||
"Infisical API returned ",
|
InfisicalApiException exception = new InfisicalApiException(message);
|
||||||
response.StatusCode.ToString(CultureInfo.InvariantCulture),
|
|
||||||
" (", response.ReasonPhrase ?? string.Empty, ")."));
|
|
||||||
exception.StatusCode = response.StatusCode;
|
exception.StatusCode = response.StatusCode;
|
||||||
exception.ReasonPhrase = response.ReasonPhrase;
|
exception.ReasonPhrase = response.ReasonPhrase;
|
||||||
exception.EndpointName = definition.Name;
|
exception.EndpointName = definition.Name;
|
||||||
exception.RequestMethod = definition.Method;
|
exception.RequestMethod = definition.Method;
|
||||||
exception.SanitizedBody = response.Body;
|
exception.SanitizedBody = response.Body;
|
||||||
|
InfisicalApiErrorEnvelope.Enrich(exception, response.Body);
|
||||||
return exception;
|
return exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -625,15 +625,14 @@ namespace PSInfisicalAPI.Secrets
|
|||||||
|
|
||||||
private static InfisicalApiException BuildApiException(InfisicalHttpResponse response, InfisicalEndpointDefinition definition)
|
private static InfisicalApiException BuildApiException(InfisicalHttpResponse response, InfisicalEndpointDefinition definition)
|
||||||
{
|
{
|
||||||
InfisicalApiException exception = new InfisicalApiException(string.Concat(
|
string message = InfisicalApiErrorEnvelope.BuildExceptionMessage(response.StatusCode, response.ReasonPhrase, response.Body);
|
||||||
"Infisical API returned ",
|
InfisicalApiException exception = new InfisicalApiException(message);
|
||||||
response.StatusCode.ToString(CultureInfo.InvariantCulture),
|
|
||||||
" (", response.ReasonPhrase ?? string.Empty, ")."));
|
|
||||||
exception.StatusCode = response.StatusCode;
|
exception.StatusCode = response.StatusCode;
|
||||||
exception.ReasonPhrase = response.ReasonPhrase;
|
exception.ReasonPhrase = response.ReasonPhrase;
|
||||||
exception.EndpointName = definition.Name;
|
exception.EndpointName = definition.Name;
|
||||||
exception.RequestMethod = definition.Method;
|
exception.RequestMethod = definition.Method;
|
||||||
exception.SanitizedBody = response.Body;
|
exception.SanitizedBody = response.Body;
|
||||||
|
InfisicalApiErrorEnvelope.Enrich(exception, response.Body);
|
||||||
return exception;
|
return exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user