Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CHECK GRANT query #68885

Merged
merged 15 commits into from
Nov 19, 2024
Merged

Add CHECK GRANT query #68885

merged 15 commits into from
Nov 19, 2024

Conversation

Unalian
Copy link
Contributor

@Unalian Unalian commented Aug 26, 2024

Changelog category (leave one):

  • New Feature

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

Add CHECK GRANT query to check whether the current user/role has been granted the specific privilege and whether the corresponding table/column exists in the memory.

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

Information about CI checks: https://clickhouse.com/docs/en/development/continuous-integration/

CI Settings (Only check the boxes if you know what you are doing):

  • Allow: All Required Checks
  • Allow: Stateless tests
  • Allow: Stateful tests
  • Allow: Integration Tests
  • Allow: Performance tests
  • Allow: All Builds
  • Allow: batch 1, 2 for multi-batch jobs
  • Allow: batch 3, 4, 5, 6 for multi-batch jobs

  • Exclude: Style check
  • Exclude: Fast test
  • Exclude: All with ASAN
  • Exclude: All with TSAN, MSAN, UBSAN, Coverage
  • Exclude: All with aarch64, release, debug

  • Run only fuzzers related jobs (libFuzzer fuzzers, AST fuzzers, etc.)
  • Exclude: AST fuzzers

  • Do not test
  • Woolen Wolfdog
  • Upload binaries for special builds
  • Disable merge-commit
  • Disable CI cache

@nikitamikhaylov nikitamikhaylov added the can be tested Allows running workflows for external contributors label Aug 26, 2024
@robot-ch-test-poll robot-ch-test-poll added the pr-feature Pull request with new product feature label Aug 26, 2024
@robot-ch-test-poll
Copy link
Contributor

robot-ch-test-poll commented Aug 26, 2024

This is an automated comment for commit 1f7be09 with description of existing statuses. It's updated for the latest CI running

✅ Click here to open a full report in a separate page

Successful checks
Check nameDescriptionStatus
BuildsThere's no description for the check yet, please add it to tests/ci/ci_config.py:CHECK_DESCRIPTIONS✅ success
Docs checkBuilds and tests the documentation✅ success
Fast testNormally this is the first check that is ran for a PR. It builds ClickHouse and runs most of stateless functional tests, omitting some. If it fails, further checks are not started until it is fixed. Look at the report to see which tests fail, then reproduce the failure locally as described here✅ success
Flaky testsChecks if new added or modified tests are flaky by running them repeatedly, in parallel, with more randomization. Functional tests are run 100 times with address sanitizer, and additional randomization of thread scheduling. Integration tests are run up to 10 times. If at least once a new test has failed, or was too long, this check will be red. We don't allow flaky tests, read the doc✅ success
Integration testsThe integration tests report. In parenthesis the package type is given, and in square brackets are the optional part/total tests✅ success
Performance ComparisonMeasure changes in query performance. The performance test report is described in detail here. In square brackets are the optional part/total tests✅ success
Stateful testsRuns stateful functional tests for ClickHouse binaries built in various configurations -- release, debug, with sanitizers, etc✅ success
Stateless testsRuns stateless functional tests for ClickHouse binaries built in various configurations -- release, debug, with sanitizers, etc✅ success
Style checkRuns a set of checks to keep the code style clean. If some of tests failed, see the related log from the report✅ success
Unit testsRuns the unit tests for different release types✅ success

@vitlibar vitlibar self-assigned this Sep 6, 2024
@Unalian
Copy link
Contributor Author

Unalian commented Sep 9, 2024

Please check the pr. The stateless test failure seems to be not related to my codes. @vitlibar @alexey-milovidov

title: "CHECK GRANT Statement"
---

The `CHECK GRANT` query is used to check whether the current user/role has been granted a specific privilege, and whether the corresponding table/column exists in the memory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Unalian Why do you think CHECK GRANT should check that the corresponding table/column exists in the memory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Unalian Why do you think CHECK GRANT should check that the corresponding table/column exists in the memory?

image Depends on the describe of the issue.

Copy link
Member

@vitlibar vitlibar Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, if a table doesn't exist then

DROP TABLE IF EXISTS db.mytable

still works, and that requires privilege GRANT DROP TABLE ON db.mytable.

But what is the point of checking the table's existence in CHECK GRANTS in this case?

CHECK GRANT DROP TABLE ON db.mytable

Copy link
Member

@vitlibar vitlibar Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we need either a setting to enable/disable checking existence in CHECK GRANT or just separate commands to check grants only or to check existence only. We already have the EXISTS TABLE command, so I think we can have EXISTS COLUMNS as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, if a table doesn't exist then

DROP TABLE IF EXISTS db.mytable

still works, and that requires privilege GRANT DROP TABLE ON db.mytable.

But what is the point of checking

CHECK GRANT DROP TABLE ON db.mytable

in this case?

CHECK GRANT DROP TABLE ON db.mytable

will return if the user has privilege to DROP TABLE ON db.mytable and the db.mytable exists.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHECK GRANT DROP TABLE ON db.mytable
will return if the user has privilege to DROP TABLE ON db.mytable and the db.mytable exists

Yes, but this is not what some users might expect from command CHECK GRANT DROP TABLE ON db.mytable in this case.

Copy link
Contributor Author

@Unalian Unalian Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we need either a setting to enable/disable checking existence in CHECK GRANT or separate commands to check grants only or to check existence only. We already have the EXISTS TABLE command, so I think we can have EXISTS COLUMNS as well.

I got your point. Separating the commands to check grants only or to check existence only may be better. Actually, that is what I am thinking about during coding(#67772 (comment)). I will change the logic here (remove the existence check in check grant). Then, maybe add EXISTS COLUMNS just like EXISTS TABLE as well.

if (!founded)
{
/// Column not found.
return executeQuery("SELECT 0 AS CHECK_GRANT", getContext(), QueryFlags{.internal = true}).second;
Copy link
Member

@vitlibar vitlibar Sep 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling executeQuery is a quite heavy way to just return 0 as a result.

It's much better to just build the result block here from scratch - in the same way how it's built in InterpreterExistsQuery:

    return QueryPipeline(std::make_shared<SourceFromSingleChunk>(Block{{
        ColumnUInt8::create(1, result),
        std::make_shared<DataTypeUInt8>(),
        "result" }}));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling executeQuery is a quite heavy way to just return 0 as a result.

It's much better to just build the result block here from scratch - in the same way how it's built in InterpreterExistsQuery:

    return QueryPipeline(std::make_shared<SourceFromSingleChunk>(Block{{
        ColumnUInt8::create(1, result),
        std::make_shared<DataTypeUInt8>(),
        "result" }}));

Got it.

}
BlockIO res;
res.pipeline = QueryPipeline(
std::make_shared<SourceFromSingleChunk>(Block{{ColumnUInt8::create(1, 1), std::make_shared<DataTypeUInt8>(), "result"}}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use user_is_granted right in the arguments of ColumnUInt8::create(), there is no need to repeat the same code again:

    BlockIO res;
    res.pipeline = QueryPipeline(
        std::make_shared<SourceFromSingleChunk>(Block{{ColumnUInt8::create(1, user_is_granted), std::make_shared<DataTypeUInt8>(), "result"}}));

Comment on lines 49 to 50
AccessRightsElements elements_to_check_grant;
collectAccessRightsElementsToGrantOrRevoke(query, elements_to_check_grant);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two lines can be replaced with just one:

Suggested change
AccessRightsElements elements_to_check_grant;
collectAccessRightsElementsToGrantOrRevoke(query, elements_to_check_grant);
const AccessRightsElements & elements_to_check_grant = query.access_rights_elements;

and function collectAccessRightsElementsToGrantOrRevoke is not needed in this file.


settings.ostr << " ";

formatElementsWithoutOptions(access_rights_elements, settings);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't you use

settings.ostr << access_rights_element.toString();

here instead of calling this function formatElementsWithoutOptions() which looks like a lot of copy-paste?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't you use

settings.ostr << access_rights_element.toString();

here instead of calling this function formatElementsWithoutOptions() which looks like a lot of copy-paste?

The function does some format works in formatFunction(). Suppose I use settings.ostr << access_rights_element.toString(); here, such query's format will be like (which is created by Parser):

:) check grant select(col,col2) on tb, alter on tb2

CHECK GRANT SELECT(col, col2) ON tb, GRANT ALTER TABLE, ALTER VIEW ON tb2

Query id: 5f3927b0-8d99-4db2-a702-67e53955476c

   ┌─result─┐
1. │      1 │
   └────────┘

1 row in set. Elapsed: 0.001 sec. 

However, the correct response should be just like GRANT keyword:


:) check grant select(col,col2) on tb, alter on tb2

CHECK GRANT SELECT(col, col2) ON tb, ALTER TABLE, ALTER VIEW ON tb2

Query id: b48aabc2-2b6e-45ed-a36a-7802a00e3852

   ┌─result─┐
1. │      1 │
   └────────┘

1 row in set. Elapsed: 0.001 sec. 

I will pollish the formatFunction here.

Copy link
Member

@vitlibar vitlibar Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main problem with your functions is that they look like a lot of copy-pasted code which isn't good. Perhaps you could get rid of at least formatColumnNames & formatONClause?

}

bool parseAccessFlagsWithColumns(IParser::Pos & pos, Expected & expected,
std::vector<std::pair<AccessFlags, Strings>> & access_and_columns)
Copy link
Member

@vitlibar vitlibar Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move common functions such as parseAccessFlags, parseColumnNames, parseAccessFlagsWithColumns, parseElements to some separate source file (src/Parser/Access/parseAccessRightsElements.h/cpp), where both ParserCheckGrantQuery.cpp and ParserGrantQuery.cpp could use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move common functions such as parseAccessFlags, parseColumnNames, parseAccessFlagsWithColumns, parseElements to some separate source file (src/Parser/Access/parseAccessRightsElements.h/cpp), where both ParserCheckGrantQuery.cpp and ParserGrantQuery.cpp could use it.

Got it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to that by myself
#72103

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to that by myself #72103

I decided to that by myself #72103

Amazing! I'm so sorry I haven't updated the code in time because I've been so busy lately :(. Thank you for your work.

@vitlibar vitlibar added this pull request to the merge queue Nov 19, 2024
Merged via the queue into ClickHouse:master with commit 353ff95 Nov 19, 2024
196 of 198 checks passed
@robot-ch-test-poll2 robot-ch-test-poll2 added the pr-synced-to-cloud The PR is synced to the cloud repo label Nov 19, 2024
@alexey-milovidov
Copy link
Member

@Unalian @vitlibar, a bug exists #74414

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
can be tested Allows running workflows for external contributors pr-feature Pull request with new product feature pr-synced-to-cloud The PR is synced to the cloud repo
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants