infrahub-server 1.1.1__py3-none-any.whl → 1.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infrahub/api/__init__.py +13 -5
- infrahub/api/artifact.py +9 -15
- infrahub/api/auth.py +7 -1
- infrahub/api/dependencies.py +15 -2
- infrahub/api/diff/diff.py +13 -7
- infrahub/api/file.py +5 -10
- infrahub/api/internal.py +19 -6
- infrahub/api/menu.py +8 -6
- infrahub/api/oauth2.py +25 -10
- infrahub/api/oidc.py +26 -10
- infrahub/api/query.py +2 -2
- infrahub/api/schema.py +48 -59
- infrahub/api/storage.py +8 -8
- infrahub/api/transformation.py +6 -5
- infrahub/auth.py +1 -26
- infrahub/cli/__init__.py +1 -1
- infrahub/cli/context.py +5 -8
- infrahub/cli/db.py +6 -6
- infrahub/cli/git_agent.py +1 -1
- infrahub/computed_attribute/models.py +1 -1
- infrahub/computed_attribute/tasks.py +1 -1
- infrahub/config.py +5 -5
- infrahub/core/account.py +2 -10
- infrahub/core/attribute.py +22 -0
- infrahub/core/branch/models.py +1 -1
- infrahub/core/branch/tasks.py +4 -3
- infrahub/core/diff/calculator.py +14 -0
- infrahub/core/diff/combiner.py +6 -2
- infrahub/core/diff/conflicts_enricher.py +2 -2
- infrahub/core/diff/coordinator.py +296 -87
- infrahub/core/diff/data_check_synchronizer.py +33 -4
- infrahub/core/diff/enricher/cardinality_one.py +3 -3
- infrahub/core/diff/enricher/hierarchy.py +4 -1
- infrahub/core/diff/merger/merger.py +11 -1
- infrahub/core/diff/merger/serializer.py +5 -29
- infrahub/core/diff/model/path.py +88 -4
- infrahub/core/diff/query/field_specifiers.py +35 -0
- infrahub/core/diff/query/roots_metadata.py +48 -0
- infrahub/core/diff/query/save.py +1 -0
- infrahub/core/diff/query_parser.py +27 -11
- infrahub/core/diff/repository/deserializer.py +7 -3
- infrahub/core/diff/repository/repository.py +100 -9
- infrahub/core/diff/tasks.py +1 -1
- infrahub/core/graph/__init__.py +1 -1
- infrahub/core/integrity/object_conflict/conflict_recorder.py +6 -1
- infrahub/core/ipam/utilization.py +6 -1
- infrahub/core/manager.py +8 -0
- infrahub/core/merge.py +6 -1
- infrahub/core/migrations/graph/__init__.py +2 -0
- infrahub/core/migrations/graph/m014_remove_index_attr_value.py +1 -1
- infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
- infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
- infrahub/core/migrations/graph/m018_uniqueness_nulls.py +101 -0
- infrahub/core/migrations/query/attribute_add.py +5 -5
- infrahub/core/migrations/schema/tasks.py +2 -2
- infrahub/core/migrations/shared.py +3 -3
- infrahub/core/node/__init__.py +8 -2
- infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
- infrahub/core/query/__init__.py +5 -2
- infrahub/core/query/diff.py +32 -19
- infrahub/core/query/ipam.py +30 -22
- infrahub/core/query/node.py +91 -40
- infrahub/core/schema/generated/attribute_schema.py +2 -2
- infrahub/core/schema/generated/base_node_schema.py +2 -2
- infrahub/core/schema/generated/relationship_schema.py +1 -1
- infrahub/core/schema/schema_branch_computed.py +1 -1
- infrahub/core/task/task_log.py +1 -1
- infrahub/core/validators/attribute/kind.py +1 -1
- infrahub/core/validators/interface.py +1 -2
- infrahub/core/validators/models/violation.py +1 -14
- infrahub/core/validators/shared.py +2 -2
- infrahub/core/validators/tasks.py +7 -4
- infrahub/core/validators/uniqueness/index.py +2 -4
- infrahub/database/index.py +1 -1
- infrahub/dependencies/builder/constraint/schema/aggregated.py +2 -0
- infrahub/dependencies/builder/constraint/schema/attribute_kind.py +8 -0
- infrahub/dependencies/builder/diff/data_check_synchronizer.py +2 -0
- infrahub/git/base.py +3 -3
- infrahub/git/integrator.py +1 -1
- infrahub/graphql/api/endpoints.py +12 -3
- infrahub/graphql/app.py +2 -2
- infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +2 -17
- infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +1 -12
- infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +6 -40
- infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -8
- infrahub/graphql/enums.py +2 -2
- infrahub/graphql/initialization.py +27 -8
- infrahub/graphql/manager.py +9 -3
- infrahub/graphql/models.py +6 -0
- infrahub/graphql/mutations/account.py +14 -10
- infrahub/graphql/mutations/computed_attribute.py +11 -22
- infrahub/graphql/mutations/diff.py +2 -0
- infrahub/graphql/mutations/main.py +5 -16
- infrahub/graphql/mutations/proposed_change.py +11 -20
- infrahub/graphql/mutations/resource_manager.py +6 -3
- infrahub/graphql/mutations/schema.py +8 -7
- infrahub/graphql/mutations/tasks.py +1 -1
- infrahub/graphql/permissions.py +3 -4
- infrahub/graphql/queries/account.py +2 -11
- infrahub/graphql/queries/resource_manager.py +21 -10
- infrahub/graphql/query.py +3 -1
- infrahub/graphql/resolvers/resolver.py +5 -1
- infrahub/graphql/types/task.py +14 -2
- infrahub/menu/generator.py +6 -18
- infrahub/message_bus/messages/event_node_mutated.py +2 -2
- infrahub/message_bus/operations/check/repository.py +2 -4
- infrahub/message_bus/operations/event/branch.py +2 -4
- infrahub/message_bus/operations/requests/proposed_change.py +1 -1
- infrahub/message_bus/operations/requests/repository.py +3 -5
- infrahub/message_bus/types.py +1 -1
- infrahub/permissions/__init__.py +12 -3
- infrahub/permissions/backend.py +2 -17
- infrahub/permissions/constants.py +12 -8
- infrahub/permissions/local_backend.py +5 -102
- infrahub/permissions/manager.py +135 -0
- infrahub/permissions/report.py +14 -25
- infrahub/permissions/types.py +6 -0
- infrahub/proposed_change/tasks.py +1 -1
- infrahub/task_manager/models.py +34 -5
- infrahub/task_manager/task.py +14 -6
- infrahub/visuals.py +1 -3
- infrahub_sdk/client.py +204 -43
- infrahub_sdk/ctl/cli_commands.py +106 -6
- infrahub_sdk/data.py +3 -2
- infrahub_sdk/graphql.py +5 -0
- infrahub_sdk/node.py +21 -2
- infrahub_sdk/queries.py +69 -0
- infrahub_sdk/schema/main.py +1 -0
- infrahub_sdk/testing/schemas/animal.py +1 -0
- infrahub_sdk/types.py +6 -0
- infrahub_sdk/utils.py +17 -0
- {infrahub_server-1.1.1.dist-info → infrahub_server-1.1.3.dist-info}/METADATA +1 -1
- {infrahub_server-1.1.1.dist-info → infrahub_server-1.1.3.dist-info}/RECORD +136 -131
- infrahub/core/diff/query/empty_roots.py +0 -33
- {infrahub_server-1.1.1.dist-info → infrahub_server-1.1.3.dist-info}/LICENSE.txt +0 -0
- {infrahub_server-1.1.1.dist-info → infrahub_server-1.1.3.dist-info}/WHEEL +0 -0
- {infrahub_server-1.1.1.dist-info → infrahub_server-1.1.3.dist-info}/entry_points.txt +0 -0
infrahub/api/__init__.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from typing import TYPE_CHECKING, NoReturn
|
|
4
|
+
|
|
5
|
+
from fastapi import APIRouter, Depends
|
|
4
6
|
from fastapi.openapi.docs import (
|
|
5
7
|
get_redoc_html,
|
|
6
8
|
get_swagger_ui_html,
|
|
7
9
|
)
|
|
8
|
-
from starlette.responses import HTMLResponse
|
|
10
|
+
from starlette.responses import HTMLResponse # noqa: TC002
|
|
9
11
|
|
|
10
12
|
from infrahub.api import (
|
|
11
13
|
artifact,
|
|
@@ -21,8 +23,12 @@ from infrahub.api import (
|
|
|
21
23
|
storage,
|
|
22
24
|
transformation,
|
|
23
25
|
)
|
|
26
|
+
from infrahub.api.dependencies import get_current_user
|
|
24
27
|
from infrahub.exceptions import ResourceNotFoundError
|
|
25
28
|
|
|
29
|
+
if TYPE_CHECKING:
|
|
30
|
+
from infrahub.auth import AccountSession
|
|
31
|
+
|
|
26
32
|
router = APIRouter(prefix="/api")
|
|
27
33
|
|
|
28
34
|
router.include_router(artifact.router)
|
|
@@ -40,7 +46,9 @@ router.include_router(transformation.router)
|
|
|
40
46
|
|
|
41
47
|
|
|
42
48
|
@router.get("/docs", include_in_schema=False)
|
|
43
|
-
async def custom_swagger_ui_html(
|
|
49
|
+
async def custom_swagger_ui_html(
|
|
50
|
+
_: AccountSession = Depends(get_current_user),
|
|
51
|
+
) -> HTMLResponse:
|
|
44
52
|
return get_swagger_ui_html(
|
|
45
53
|
openapi_url="/api/openapi.json",
|
|
46
54
|
title="Infrahub - Swagger UI",
|
|
@@ -50,7 +58,7 @@ async def custom_swagger_ui_html() -> HTMLResponse:
|
|
|
50
58
|
|
|
51
59
|
|
|
52
60
|
@router.get("/redoc", include_in_schema=False)
|
|
53
|
-
async def redoc_html() -> HTMLResponse:
|
|
61
|
+
async def redoc_html(_: AccountSession = Depends(get_current_user)) -> HTMLResponse:
|
|
54
62
|
return get_redoc_html(
|
|
55
63
|
openapi_url="/api/openapi.json",
|
|
56
64
|
title="Infrahub - ReDoc",
|
infrahub/api/artifact.py
CHANGED
|
@@ -5,13 +5,13 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
from fastapi import APIRouter, Body, Depends, Request, Response
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
8
|
-
from infrahub.api.dependencies import BranchParams, get_branch_params, get_current_user, get_db
|
|
8
|
+
from infrahub.api.dependencies import BranchParams, get_branch_params, get_current_user, get_db, get_permission_manager
|
|
9
9
|
from infrahub.core import registry
|
|
10
10
|
from infrahub.core.account import ObjectPermission
|
|
11
11
|
from infrahub.core.constants import GLOBAL_BRANCH_NAME, InfrahubKind, PermissionAction
|
|
12
12
|
from infrahub.core.protocols import CoreArtifactDefinition
|
|
13
|
-
from infrahub.database import InfrahubDatabase # noqa:
|
|
14
|
-
from infrahub.exceptions import NodeNotFoundError
|
|
13
|
+
from infrahub.database import InfrahubDatabase # noqa: TC001
|
|
14
|
+
from infrahub.exceptions import NodeNotFoundError
|
|
15
15
|
from infrahub.git.models import RequestArtifactDefinitionGenerate
|
|
16
16
|
from infrahub.log import get_logger
|
|
17
17
|
from infrahub.permissions.constants import PermissionDecisionFlag
|
|
@@ -19,6 +19,7 @@ from infrahub.workflows.catalogue import REQUEST_ARTIFACT_DEFINITION_GENERATE
|
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from infrahub.auth import AccountSession
|
|
22
|
+
from infrahub.permissions import PermissionManager
|
|
22
23
|
|
|
23
24
|
log = get_logger()
|
|
24
25
|
router = APIRouter(prefix="/artifact")
|
|
@@ -37,7 +38,7 @@ async def get_artifact(
|
|
|
37
38
|
artifact_id: str,
|
|
38
39
|
db: InfrahubDatabase = Depends(get_db),
|
|
39
40
|
branch_params: BranchParams = Depends(get_branch_params),
|
|
40
|
-
_:
|
|
41
|
+
_: AccountSession = Depends(get_current_user),
|
|
41
42
|
) -> Response:
|
|
42
43
|
artifact = await registry.manager.get_one(db=db, id=artifact_id, branch=branch_params.branch, at=branch_params.at)
|
|
43
44
|
if not artifact:
|
|
@@ -61,25 +62,18 @@ async def generate_artifact(
|
|
|
61
62
|
),
|
|
62
63
|
db: InfrahubDatabase = Depends(get_db),
|
|
63
64
|
branch_params: BranchParams = Depends(get_branch_params),
|
|
64
|
-
|
|
65
|
+
permission_manager: PermissionManager = Depends(get_permission_manager),
|
|
65
66
|
) -> None:
|
|
66
67
|
permission_decision = (
|
|
67
68
|
PermissionDecisionFlag.ALLOW_DEFAULT
|
|
68
69
|
if branch_params.branch.name in (GLOBAL_BRANCH_NAME, registry.default_branch)
|
|
69
70
|
else PermissionDecisionFlag.ALLOW_OTHER
|
|
70
71
|
)
|
|
71
|
-
|
|
72
|
+
permissions = [
|
|
72
73
|
ObjectPermission(namespace="Core", name="Artifact", action=action.value, decision=permission_decision)
|
|
73
74
|
for action in (PermissionAction.CREATE, PermissionAction.UPDATE)
|
|
74
|
-
]
|
|
75
|
-
|
|
76
|
-
for permission_backend in registry.permission_backends:
|
|
77
|
-
if has_permission := await permission_backend.has_permission(
|
|
78
|
-
db=db, account_session=account_session, permission=permission, branch=branch_params.branch
|
|
79
|
-
):
|
|
80
|
-
break
|
|
81
|
-
if not has_permission:
|
|
82
|
-
raise PermissionDeniedError(f"You do not have the following permission: {permission}")
|
|
75
|
+
]
|
|
76
|
+
permission_manager.raise_for_permissions(permissions=permissions)
|
|
83
77
|
|
|
84
78
|
# Verify that the artifact definition exists for the requested branch
|
|
85
79
|
artifact_definition = await registry.manager.get_one_by_id_or_default_filter(
|
infrahub/api/auth.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
1
5
|
from fastapi import APIRouter, Depends, Response
|
|
2
6
|
|
|
3
7
|
from infrahub import config, models
|
|
@@ -8,7 +12,9 @@ from infrahub.auth import (
|
|
|
8
12
|
create_fresh_access_token,
|
|
9
13
|
invalidate_refresh_token,
|
|
10
14
|
)
|
|
11
|
-
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from infrahub.database import InfrahubDatabase
|
|
12
18
|
|
|
13
19
|
router = APIRouter(prefix="/auth")
|
|
14
20
|
|
infrahub/api/dependencies.py
CHANGED
|
@@ -8,11 +8,12 @@ from pydantic import BaseModel, ConfigDict
|
|
|
8
8
|
|
|
9
9
|
from infrahub import config
|
|
10
10
|
from infrahub.auth import AccountSession, authentication_token, validate_jwt_access_token, validate_jwt_refresh_token
|
|
11
|
-
from infrahub.core.branch import Branch # noqa:
|
|
11
|
+
from infrahub.core.branch import Branch # noqa: TC001
|
|
12
12
|
from infrahub.core.registry import registry
|
|
13
13
|
from infrahub.core.timestamp import Timestamp
|
|
14
|
-
from infrahub.database import InfrahubDatabase # noqa:
|
|
14
|
+
from infrahub.database import InfrahubDatabase # noqa: TC001
|
|
15
15
|
from infrahub.exceptions import AuthorizationError
|
|
16
|
+
from infrahub.permissions import PermissionManager
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
18
19
|
from neo4j import AsyncSession
|
|
@@ -120,3 +121,15 @@ async def get_current_user(
|
|
|
120
121
|
return account_session
|
|
121
122
|
|
|
122
123
|
raise AuthorizationError("Authentication is required")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
async def get_permission_manager(
|
|
127
|
+
db: InfrahubDatabase = Depends(get_db),
|
|
128
|
+
branch_params: BranchParams = Depends(get_branch_params),
|
|
129
|
+
account_session: AccountSession = Depends(get_current_user),
|
|
130
|
+
) -> PermissionManager:
|
|
131
|
+
"""Return a `PermissionManager` for an account session based on a branch."""
|
|
132
|
+
permission_manager = PermissionManager(account_session=account_session)
|
|
133
|
+
await permission_manager.load_permissions(db=db, branch=branch_params.branch)
|
|
134
|
+
|
|
135
|
+
return permission_manager
|
infrahub/api/diff/diff.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections import defaultdict
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
6
|
from fastapi import APIRouter, Depends, Request
|
|
7
7
|
|
|
8
8
|
from infrahub.api.dependencies import get_branch_dep, get_current_user, get_db
|
|
9
9
|
from infrahub.core import registry
|
|
10
|
-
from infrahub.core.branch import Branch # noqa: TCH001
|
|
11
10
|
from infrahub.core.diff.artifacts.calculator import ArtifactDiffCalculator
|
|
12
11
|
from infrahub.core.diff.branch_differ import BranchDiffer
|
|
13
12
|
from infrahub.core.diff.model.diff import (
|
|
@@ -15,9 +14,11 @@ from infrahub.core.diff.model.diff import (
|
|
|
15
14
|
BranchDiffFile,
|
|
16
15
|
BranchDiffRepository,
|
|
17
16
|
)
|
|
18
|
-
from infrahub.database import InfrahubDatabase # noqa: TCH001
|
|
19
17
|
|
|
20
18
|
if TYPE_CHECKING:
|
|
19
|
+
from infrahub.auth import AccountSession
|
|
20
|
+
from infrahub.core.branch import Branch
|
|
21
|
+
from infrahub.database import InfrahubDatabase
|
|
21
22
|
from infrahub.services import InfrahubServices
|
|
22
23
|
|
|
23
24
|
|
|
@@ -29,17 +30,22 @@ async def get_diff_files(
|
|
|
29
30
|
request: Request,
|
|
30
31
|
db: InfrahubDatabase = Depends(get_db),
|
|
31
32
|
branch: Branch = Depends(get_branch_dep),
|
|
32
|
-
time_from:
|
|
33
|
-
time_to:
|
|
33
|
+
time_from: str | None = None,
|
|
34
|
+
time_to: str | None = None,
|
|
34
35
|
branch_only: bool = True,
|
|
35
|
-
_:
|
|
36
|
+
_: AccountSession = Depends(get_current_user),
|
|
36
37
|
) -> dict[str, dict[str, BranchDiffRepository]]:
|
|
37
38
|
response: dict[str, dict[str, BranchDiffRepository]] = defaultdict(dict)
|
|
38
39
|
service: InfrahubServices = request.app.state.service
|
|
39
40
|
|
|
40
41
|
# Query the Diff for all files and repository from the database
|
|
41
42
|
diff = await BranchDiffer.init(
|
|
42
|
-
db=db,
|
|
43
|
+
db=db,
|
|
44
|
+
branch=branch,
|
|
45
|
+
diff_from=time_from,
|
|
46
|
+
diff_to=time_to,
|
|
47
|
+
branch_only=branch_only,
|
|
48
|
+
service=service,
|
|
43
49
|
)
|
|
44
50
|
diff_files = await diff.get_files()
|
|
45
51
|
|
infrahub/api/file.py
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from fastapi import APIRouter, Depends, Request
|
|
6
6
|
from starlette.responses import PlainTextResponse
|
|
7
7
|
|
|
8
|
-
from infrahub.api.dependencies import
|
|
9
|
-
BranchParams,
|
|
10
|
-
get_branch_params,
|
|
11
|
-
get_current_user,
|
|
12
|
-
get_db,
|
|
13
|
-
)
|
|
8
|
+
from infrahub.api.dependencies import BranchParams, get_branch_params, get_current_user, get_db
|
|
14
9
|
from infrahub.core.constants import InfrahubKind
|
|
15
10
|
from infrahub.core.manager import NodeManager
|
|
16
|
-
from infrahub.database import InfrahubDatabase # noqa:
|
|
11
|
+
from infrahub.database import InfrahubDatabase # noqa: TC001
|
|
17
12
|
from infrahub.exceptions import CommitNotFoundError, PropagatedFromWorkerError
|
|
18
13
|
from infrahub.message_bus.messages import GitFileGet, GitFileGetResponse
|
|
19
14
|
|
|
@@ -32,13 +27,13 @@ async def get_file(
|
|
|
32
27
|
file_path: str,
|
|
33
28
|
branch_params: BranchParams = Depends(get_branch_params),
|
|
34
29
|
db: InfrahubDatabase = Depends(get_db),
|
|
35
|
-
commit:
|
|
30
|
+
commit: str | None = None,
|
|
36
31
|
_: str = Depends(get_current_user),
|
|
37
32
|
) -> PlainTextResponse:
|
|
38
33
|
"""Retrieve a file from a git repository."""
|
|
39
34
|
service: InfrahubServices = request.app.state.service
|
|
40
35
|
|
|
41
|
-
repo:
|
|
36
|
+
repo: CoreRepository | CoreReadOnlyRepository = await NodeManager.get_one_by_id_or_default_filter(
|
|
42
37
|
db=db,
|
|
43
38
|
id=repository_id,
|
|
44
39
|
kind=InfrahubKind.GENERICREPOSITORY,
|
infrahub/api/internal.py
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
|
-
from typing import
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
3
5
|
|
|
4
6
|
import ujson
|
|
5
|
-
from fastapi import APIRouter, Request
|
|
7
|
+
from fastapi import APIRouter, Depends, Request
|
|
6
8
|
from lunr.index import Index
|
|
7
9
|
from pydantic import BaseModel
|
|
8
10
|
|
|
9
11
|
from infrahub import config
|
|
10
|
-
from infrahub.
|
|
12
|
+
from infrahub.api.dependencies import get_current_user
|
|
13
|
+
from infrahub.config import ( # noqa: TC001
|
|
14
|
+
AnalyticsSettings,
|
|
15
|
+
ExperimentalFeaturesSettings,
|
|
16
|
+
LoggingSettings,
|
|
17
|
+
MainSettings,
|
|
18
|
+
)
|
|
11
19
|
from infrahub.core import registry
|
|
12
20
|
from infrahub.exceptions import NodeNotFoundError
|
|
13
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from infrahub.auth import AccountSession
|
|
24
|
+
|
|
14
25
|
router = APIRouter()
|
|
15
26
|
|
|
16
27
|
|
|
@@ -39,7 +50,7 @@ async def get_config() -> ConfigAPI:
|
|
|
39
50
|
|
|
40
51
|
|
|
41
52
|
@router.get("/info")
|
|
42
|
-
async def get_info(request: Request) -> InfoAPI:
|
|
53
|
+
async def get_info(request: Request, _: AccountSession = Depends(get_current_user)) -> InfoAPI:
|
|
43
54
|
return InfoAPI(deployment_id=str(registry.id), version=request.app.version)
|
|
44
55
|
|
|
45
56
|
|
|
@@ -47,7 +58,7 @@ class SearchDocs:
|
|
|
47
58
|
def __init__(self) -> None:
|
|
48
59
|
self._title_documents: list[dict] = []
|
|
49
60
|
self._heading_documents: list[dict] = []
|
|
50
|
-
self._heading_index:
|
|
61
|
+
self._heading_index: Index | None = None
|
|
51
62
|
|
|
52
63
|
def _load_json(self) -> None:
|
|
53
64
|
"""
|
|
@@ -142,7 +153,9 @@ class SearchResultAPI(BaseModel):
|
|
|
142
153
|
|
|
143
154
|
|
|
144
155
|
@router.get("/search/docs", include_in_schema=False)
|
|
145
|
-
async def search_docs(
|
|
156
|
+
async def search_docs(
|
|
157
|
+
query: str, limit: int | None = None, _: AccountSession = Depends(get_current_user)
|
|
158
|
+
) -> list[SearchResultAPI]:
|
|
146
159
|
smart_query = smart_queries(query)
|
|
147
160
|
search_results = search_docs_loader.heading_index.search(smart_query)
|
|
148
161
|
heading_results = [
|
infrahub/api/menu.py
CHANGED
|
@@ -4,17 +4,17 @@ from typing import TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
from fastapi import APIRouter, Depends
|
|
6
6
|
|
|
7
|
-
from infrahub.api.dependencies import get_branch_dep,
|
|
7
|
+
from infrahub.api.dependencies import get_branch_dep, get_db, get_permission_manager
|
|
8
8
|
from infrahub.core import registry
|
|
9
|
-
from infrahub.core.branch import Branch # noqa:
|
|
9
|
+
from infrahub.core.branch import Branch # noqa: TC001
|
|
10
10
|
from infrahub.core.protocols import CoreMenuItem
|
|
11
11
|
from infrahub.log import get_logger
|
|
12
12
|
from infrahub.menu.generator import generate_restricted_menu
|
|
13
|
-
from infrahub.menu.models import Menu # noqa:
|
|
13
|
+
from infrahub.menu.models import Menu # noqa: TC001
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
|
-
from infrahub.auth import AccountSession
|
|
17
16
|
from infrahub.database import InfrahubDatabase
|
|
17
|
+
from infrahub.permissions import PermissionManager
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
log = get_logger()
|
|
@@ -25,10 +25,12 @@ router = APIRouter(prefix="/menu")
|
|
|
25
25
|
async def get_menu(
|
|
26
26
|
db: InfrahubDatabase = Depends(get_db),
|
|
27
27
|
branch: Branch = Depends(get_branch_dep),
|
|
28
|
-
|
|
28
|
+
permission_manager: PermissionManager = Depends(get_permission_manager),
|
|
29
29
|
) -> Menu:
|
|
30
30
|
log.info("menu_request", branch=branch.name)
|
|
31
31
|
|
|
32
32
|
menu_items = await registry.manager.query(db=db, schema=CoreMenuItem, branch=branch, prefetch_relationships=True)
|
|
33
|
-
menu = await generate_restricted_menu(
|
|
33
|
+
menu = await generate_restricted_menu(
|
|
34
|
+
db=db, branch=branch, menu_items=menu_items, account_permissions=permission_manager
|
|
35
|
+
)
|
|
34
36
|
return menu.to_rest()
|
infrahub/api/oauth2.py
CHANGED
|
@@ -3,9 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
from urllib.parse import urljoin
|
|
5
5
|
|
|
6
|
+
import ujson
|
|
6
7
|
from authlib.integrations.httpx_client import AsyncOAuth2Client
|
|
7
8
|
from fastapi import APIRouter, Depends, Request, Response
|
|
8
9
|
from fastapi.responses import JSONResponse, RedirectResponse
|
|
10
|
+
from opentelemetry import trace
|
|
9
11
|
|
|
10
12
|
from infrahub import config, models
|
|
11
13
|
from infrahub.api.dependencies import get_db
|
|
@@ -20,27 +22,34 @@ if TYPE_CHECKING:
|
|
|
20
22
|
from infrahub.database import InfrahubDatabase
|
|
21
23
|
from infrahub.services import InfrahubServices
|
|
22
24
|
|
|
25
|
+
# pylint: disable=R0801
|
|
26
|
+
|
|
23
27
|
log = get_logger()
|
|
24
28
|
router = APIRouter(prefix="/oauth2")
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
def _get_redirect_url(request: Request, provider_name: str) -> str:
|
|
28
|
-
"""
|
|
29
|
-
base_url = config.SETTINGS.
|
|
32
|
+
"""Return public redirect URL."""
|
|
33
|
+
base_url = config.SETTINGS.main.public_url or str(request.base_url)
|
|
30
34
|
return urljoin(base_url, f"auth/oauth2/{provider_name}/callback")
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
@router.get("/{provider_name:str}/authorize")
|
|
34
38
|
async def authorize(request: Request, provider_name: str, final_url: str | None = None) -> Response:
|
|
35
39
|
provider = config.SETTINGS.security.get_oauth2_provider(provider=provider_name)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
with trace.get_tracer(__name__).start_as_current_span("sso_oauth2_client_configuration") as span:
|
|
42
|
+
span.set_attribute("provider_name", provider_name)
|
|
43
|
+
span.set_attribute("scopes", provider.scopes)
|
|
44
|
+
|
|
45
|
+
client = AsyncOAuth2Client(
|
|
46
|
+
client_id=provider.client_id,
|
|
47
|
+
client_secret=provider.client_secret,
|
|
48
|
+
scope=provider.scopes,
|
|
49
|
+
)
|
|
41
50
|
|
|
42
51
|
redirect_uri = _get_redirect_url(request=request, provider_name=provider_name)
|
|
43
|
-
final_url = final_url or config.SETTINGS.
|
|
52
|
+
final_url = final_url or config.SETTINGS.main.public_url or str(request.base_url)
|
|
44
53
|
|
|
45
54
|
authorization_uri, state = client.create_authorization_url(
|
|
46
55
|
url=provider.authorization_url, redirect_uri=redirect_uri, scope=provider.scopes, final_url=final_url
|
|
@@ -88,7 +97,10 @@ async def token(
|
|
|
88
97
|
|
|
89
98
|
token_response = await service.http.post(provider.token_url, data=token_data)
|
|
90
99
|
_validate_response(response=token_response)
|
|
91
|
-
|
|
100
|
+
|
|
101
|
+
with trace.get_tracer(__name__).start_as_current_span("sso_token_request") as span:
|
|
102
|
+
span.set_attribute("token_request_data", ujson.dumps(token_response.json()))
|
|
103
|
+
payload = token_response.json()
|
|
92
104
|
|
|
93
105
|
headers = {"Authorization": f"{payload.get('token_type')} {payload.get('access_token')}"}
|
|
94
106
|
if provider.userinfo_method == config.UserInfoMethod.GET:
|
|
@@ -102,7 +114,10 @@ async def token(
|
|
|
102
114
|
if not sso_groups and config.SETTINGS.security.sso_user_default_group:
|
|
103
115
|
sso_groups = [config.SETTINGS.security.sso_user_default_group]
|
|
104
116
|
|
|
105
|
-
|
|
117
|
+
with trace.get_tracer(__name__).start_as_current_span("signin_sso_account") as span:
|
|
118
|
+
span.set_attribute("account_name", ujson.dumps(userinfo_response.json()))
|
|
119
|
+
span.set_attribute("sso_groups", sso_groups)
|
|
120
|
+
user_token = await signin_sso_account(db=db, account_name=user_info["name"], sso_groups=sso_groups)
|
|
106
121
|
|
|
107
122
|
response.set_cookie(
|
|
108
123
|
"access_token", user_token.access_token, httponly=True, max_age=config.SETTINGS.security.access_token_lifetime
|
infrahub/api/oidc.py
CHANGED
|
@@ -3,9 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
from urllib.parse import urljoin
|
|
5
5
|
|
|
6
|
+
import ujson
|
|
6
7
|
from authlib.integrations.httpx_client import AsyncOAuth2Client
|
|
7
8
|
from fastapi import APIRouter, Depends, Request, Response
|
|
8
9
|
from fastapi.responses import JSONResponse, RedirectResponse
|
|
10
|
+
from opentelemetry import trace
|
|
9
11
|
from pydantic import BaseModel, HttpUrl
|
|
10
12
|
|
|
11
13
|
from infrahub import config, models
|
|
@@ -21,6 +23,8 @@ if TYPE_CHECKING:
|
|
|
21
23
|
from infrahub.database import InfrahubDatabase
|
|
22
24
|
from infrahub.services import InfrahubServices
|
|
23
25
|
|
|
26
|
+
# pylint: disable=R0801
|
|
27
|
+
|
|
24
28
|
log = get_logger()
|
|
25
29
|
router = APIRouter(prefix="/oidc")
|
|
26
30
|
|
|
@@ -54,8 +58,8 @@ class OIDCDiscoveryConfig(BaseModel):
|
|
|
54
58
|
|
|
55
59
|
|
|
56
60
|
def _get_redirect_url(request: Request, provider_name: str) -> str:
|
|
57
|
-
"""
|
|
58
|
-
base_url = config.SETTINGS.
|
|
61
|
+
"""Return public redirect URL."""
|
|
62
|
+
base_url = config.SETTINGS.main.public_url or str(request.base_url)
|
|
59
63
|
return urljoin(base_url, f"auth/oidc/{provider_name}/callback")
|
|
60
64
|
|
|
61
65
|
|
|
@@ -68,14 +72,19 @@ async def authorize(request: Request, provider_name: str, final_url: str | None
|
|
|
68
72
|
_validate_response(response=response)
|
|
69
73
|
oidc_config = OIDCDiscoveryConfig(**response.json())
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
with trace.get_tracer(__name__).start_as_current_span("sso_oauth2_client_configuration") as span:
|
|
76
|
+
span.set_attribute("provider_name", provider_name)
|
|
77
|
+
span.set_attribute("scopes", provider.scopes)
|
|
78
|
+
span.set_attribute("discovery_url", provider.discovery_url)
|
|
79
|
+
|
|
80
|
+
client = AsyncOAuth2Client(
|
|
81
|
+
client_id=provider.client_id,
|
|
82
|
+
client_secret=provider.client_secret,
|
|
83
|
+
scope=provider.scopes,
|
|
84
|
+
)
|
|
76
85
|
|
|
77
86
|
redirect_uri = _get_redirect_url(request=request, provider_name=provider_name)
|
|
78
|
-
final_url = final_url or config.SETTINGS.
|
|
87
|
+
final_url = final_url or config.SETTINGS.main.public_url or str(request.base_url)
|
|
79
88
|
|
|
80
89
|
authorization_uri, state = client.create_authorization_url(
|
|
81
90
|
url=str(oidc_config.authorization_endpoint), redirect_uri=redirect_uri, scope=provider.scopes
|
|
@@ -126,7 +135,10 @@ async def token(
|
|
|
126
135
|
|
|
127
136
|
token_response = await service.http.post(str(oidc_config.token_endpoint), data=token_data)
|
|
128
137
|
_validate_response(response=token_response)
|
|
129
|
-
|
|
138
|
+
|
|
139
|
+
with trace.get_tracer(__name__).start_as_current_span("sso_token_request") as span:
|
|
140
|
+
span.set_attribute("token_request_data", ujson.dumps(token_response.json()))
|
|
141
|
+
payload = token_response.json()
|
|
130
142
|
|
|
131
143
|
headers = {"Authorization": f"{payload.get('token_type')} {payload.get('access_token')}"}
|
|
132
144
|
|
|
@@ -138,10 +150,14 @@ async def token(
|
|
|
138
150
|
_validate_response(response=userinfo_response)
|
|
139
151
|
user_info = userinfo_response.json()
|
|
140
152
|
sso_groups = user_info.get("groups", [])
|
|
153
|
+
|
|
141
154
|
if not sso_groups and config.SETTINGS.security.sso_user_default_group:
|
|
142
155
|
sso_groups = [config.SETTINGS.security.sso_user_default_group]
|
|
143
156
|
|
|
144
|
-
|
|
157
|
+
with trace.get_tracer(__name__).start_as_current_span("signin_sso_account") as span:
|
|
158
|
+
span.set_attribute("account_name", ujson.dumps(userinfo_response.json()))
|
|
159
|
+
span.set_attribute("sso_groups", sso_groups)
|
|
160
|
+
user_token = await signin_sso_account(db=db, account_name=user_info["name"], sso_groups=sso_groups)
|
|
145
161
|
|
|
146
162
|
response.set_cookie(
|
|
147
163
|
"access_token", user_token.access_token, httponly=True, max_age=config.SETTINGS.security.access_token_lifetime
|
infrahub/api/query.py
CHANGED
|
@@ -10,7 +10,7 @@ from infrahub.api.dependencies import BranchParams, get_branch_params, get_curre
|
|
|
10
10
|
from infrahub.core import registry
|
|
11
11
|
from infrahub.core.constants import InfrahubKind
|
|
12
12
|
from infrahub.core.protocols import CoreGraphQLQuery
|
|
13
|
-
from infrahub.database import InfrahubDatabase # noqa:
|
|
13
|
+
from infrahub.database import InfrahubDatabase # noqa: TC001
|
|
14
14
|
from infrahub.graphql.analyzer import InfrahubGraphQLQueryAnalyzer
|
|
15
15
|
from infrahub.graphql.api.dependencies import build_graphql_query_permission_checker
|
|
16
16
|
from infrahub.graphql.initialization import prepare_graphql_params
|
|
@@ -57,7 +57,7 @@ async def execute_query(
|
|
|
57
57
|
db=db, id=query_id, kind=CoreGraphQLQuery, branch=branch_params.branch, at=branch_params.at
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
-
gql_params = prepare_graphql_params(
|
|
60
|
+
gql_params = await prepare_graphql_params(
|
|
61
61
|
db=db, branch=branch_params.branch, at=branch_params.at, account_session=account_session
|
|
62
62
|
)
|
|
63
63
|
analyzed_query = InfrahubGraphQLQueryAnalyzer(
|