Optional Engine::SetProcedure()

in src/modules/compliance/src/lib/Engine.cpp [113:207]


Optional<Error> Engine::SetProcedure(const std::string& ruleName, const std::string& payload)
{
    if (ruleName.empty())
    {
        return Error("Rule name is empty", EINVAL);
    }

    mDatabase.erase(ruleName);
    auto ruleJSON = DecodeB64Json(payload);
    if (!ruleJSON.HasValue())
    {
        // Fall back to plain JSON, both formats are supported
        ruleJSON = compliance::ParseJson(payload.c_str());
        if (!ruleJSON.HasValue())
        {
            OsConfigLogError(Log(), "Failed to parse JSON: %s", ruleJSON.Error().message.c_str());
            return ruleJSON.Error();
        }
    }

    auto object = json_value_get_object(ruleJSON.Value().get());
    if (nullptr == object)
    {
        return Error("Failed to parse JSON object");
    }

    auto jsonValue = json_object_get_value(object, "audit");
    if (nullptr == jsonValue)
    {
        return Error("Missing 'audit' object");
    }

    if (json_value_get_type(jsonValue) != JSONObject)
    {
        return Error("The 'audit' value is not an object");
    }

    auto procedure = Procedure{};
    auto error = procedure.SetAudit(jsonValue);
    if (error)
    {
        return error.Value();
    }
    if (nullptr == procedure.Audit())
    {
        OsConfigLogError(Log(), "Failed to copy 'audit' object");
        return Error("Out of memory");
    }

    jsonValue = json_object_get_value(object, "remediate");
    if (nullptr != jsonValue)
    {
        if (json_value_get_type(jsonValue) != JSONObject)
        {
            return Error("The 'remediate' value is not an object");
        }

        error = procedure.SetRemediation(jsonValue);
        if (error)
        {
            return error.Value();
        }
        if (nullptr == procedure.Remediation())
        {
            OsConfigLogError(Log(), "Failed to copy 'remediate' object");
            return Error("Out of memory");
        }
    }

    jsonValue = json_object_get_value(object, "parameters");
    if (nullptr != jsonValue)
    {
        if (json_value_get_type(jsonValue) != JSONObject)
        {
            return Error("The 'parameters' value is not an object");
        }

        auto paramsObj = json_value_get_object(jsonValue);
        auto count = json_object_get_count(paramsObj);
        for (decltype(count) i = 0; i < count; ++i)
        {
            const char* key = json_object_get_name(paramsObj, i);
            const char* val = json_object_get_string(paramsObj, key);
            if ((nullptr == key) || (nullptr == val))
            {
                OsConfigLogError(Log(), "Failed to get parameter name and value");
                return Error("Failed to get parameter name and value");
            }

            procedure.SetParameter(key, val);
        }
    }
    mDatabase.emplace(std::move(ruleName), std::move(procedure));
    return Optional<Error>();
}