Updated Branches: refs/heads/master 8fc91c54f -> a9f9790ba
SENTRY-90: Normalize scratch path for comparison (Brock Noland via Shreepadma Venugopalan) Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/a9f9790b Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/a9f9790b Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/a9f9790b Branch: refs/heads/master Commit: a9f9790ba1f0a606e286e3ab813b2b2f319b70a8 Parents: 8fc91c5 Author: Shreepadma Venugopalan <[email protected]> Authored: Mon Jan 20 13:58:41 2014 -0800 Committer: Shreepadma Venugopalan <[email protected]> Committed: Mon Jan 20 13:58:41 2014 -0800 ---------------------------------------------------------------------- pom.xml | 27 ++-- .../binding/hive/HiveAuthzBindingHook.java | 63 +++------ sentry-core/sentry-core-common/pom.xml | 12 ++ .../sentry/core/common/utils/PathUtils.java | 131 +++++++++++++++++++ .../sentry/core/common/utils/TestPathUtils.java | 76 +++++++++++ .../sentry/policy/db/DBWildcardPermission.java | 54 ++------ sentry-provider/sentry-provider-file/pom.xml | 4 + sentry-tests/sentry-tests-hive/.gitignore | 2 + 8 files changed, 271 insertions(+), 98 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 7fd7696..2f70df1 100644 --- a/pom.xml +++ b/pom.xml @@ -52,24 +52,29 @@ limitations under the License. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compile.source>1.6</maven.compile.source> <maven.compile.target>1.6</maven.compile.target> + <commons.lang.version>2.6</commons.lang.version> + <derby.version>10.4.2.0</derby.version> + <fest.reflect.version>1.4.1</fest.reflect.version> + <guava.version>11.0.2</guava.version> + <hadoop.version>2.0.0-cdh4.4.0</hadoop.version> <hive.version>0.10.0-cdh4.4.0</hive.version> - <hadoop.version>2.0.0-cdh4.4.</hadoop.version> - <solr.version>4.4.0-cdh5.0.0-SNAPSHOT</solr.version> <junit.version>4.9</junit.version> - <fest.reflect.version>1.4.1</fest.reflect.version> + <libthrift.version>0.9.0-cdh4-1</libthrift.version> <log4j.version>1.2.16</log4j.version> - <guava.version>11.0.2</guava.version> <shiro.version>1.2.1</shiro.version> <slf4j.version>1.6.1</slf4j.version> - <derby.version>10.4.2.0</derby.version> - <libthrift.version>0.9.0-cdh4-1</libthrift.version> - <hadoop.version>2.0.0-cdh4.4.0</hadoop.version> + <solr.version>4.4.0-cdh5.0.0-SNAPSHOT</solr.version> <zookeeper.version>3.4.5-cdh4.4.0</zookeeper.version> </properties> <dependencyManagement> <dependencies> <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>${commons.lang.version}</version> + </dependency> + <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> <version>${derby.version}</version> @@ -352,11 +357,11 @@ limitations under the License. <exclude>**/nb-configuration.xml</exclude> <exclude>**.patch</exclude> <exclude>README*</exclude> - <exclude>.project</exclude> + <exclude>**/.project</exclude> <exclude>**/target/</exclude> - <exclude>.settings</exclude> - <exclude>.metadata/</exclude> - <exclude>.classpath</exclude> + <exclude>**/.settings/**</exclude> + <exclude>**/.metadata/</exclude> + <exclude>**/.classpath</exclude> <exclude>**/service.properties</exclude> <exclude>**/kv1.dat</exclude> <exclude>**/*.lck</exclude> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java ---------------------------------------------------------------------- diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java index 0dd28b7..9852c9e 100644 --- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java +++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java @@ -62,6 +62,7 @@ import org.apache.sentry.binding.hive.authz.HiveAuthzPrivilegesMap; import org.apache.sentry.binding.hive.conf.HiveAuthzConf; import org.apache.sentry.core.common.Action; import org.apache.sentry.core.common.Subject; +import org.apache.sentry.core.common.utils.PathUtils; import org.apache.sentry.core.model.db.AccessURI; import org.apache.sentry.core.model.db.Database; import org.apache.sentry.core.model.db.DBModelAction; @@ -251,41 +252,16 @@ implements HiveDriverFilterHook { @VisibleForTesting protected static AccessURI parseURI(String uri, boolean isLocal) throws SemanticException { - if (!(uri.startsWith("file://") || uri.startsWith("hdfs://"))) { - if (uri.startsWith("file:")) { - uri = uri.replace("file:", "file://"); - } else if (uri.startsWith("/")) { - String wareHouseDir = SessionState.get().getConf() - .get(ConfVars.METASTOREWAREHOUSE.varname); - if (wareHouseDir.startsWith("hdfs:")) { - URI warehouse = toDFSURI(wareHouseDir); - uri = warehouse.getScheme() + "://" + warehouse.getAuthority() + uri; - } else if (wareHouseDir.startsWith("file:")) { - uri = "file://" + uri; - } else { - if (isLocal) { - uri = "file://" + uri; - } else { - uri = "hdfs://" + uri; - } - } - } - return new AccessURI(uri); - } - return new AccessURI(uri); - } - - private static URI toDFSURI(String s) throws SemanticException { try { - URI uri = new URI(s); - if(uri.getScheme() == null || uri.getAuthority() == null) { - throw new SemanticException("Invalid URI " + s + ". No scheme or authority."); - } - return uri; - } catch (URISyntaxException e) { - throw new SemanticException("Invalid URI " + s, e); + HiveConf conf = SessionState.get().getConf(); + String warehouseDir = conf.getVar(ConfVars.METASTOREWAREHOUSE); + return new AccessURI(PathUtils.parseDFSURI(warehouseDir, uri, isLocal)); + } catch (Exception e) { + throw new SemanticException("Error parsing URI " + uri + ": " + + e.getMessage(), e); } } + /** * Post analyze hook that invokes hive auth bindings */ @@ -378,7 +354,6 @@ implements HiveDriverFilterHook { } continue; } - List<DBModelAuthorizable> entityHierarchy = new ArrayList<DBModelAuthorizable>(); entityHierarchy.add(hiveAuthzBinding.getAuthServer()); entityHierarchy.addAll(getAuthzHierarchyFromEntity(readEntity)); @@ -469,7 +444,7 @@ implements HiveDriverFilterHook { private boolean isUDF(ReadEntity readEntity) { return readEntity.getType().equals(Type.UDF); } - + private boolean isBuiltinUDF(ReadEntity readEntity) { return readEntity.getType().equals(Type.UDF) && readEntity.getUDF().isNative(); @@ -538,19 +513,17 @@ implements HiveDriverFilterHook { if (writeEntity.getTyp().equals(Type.DFS_DIR) || writeEntity.getTyp().equals(Type.LOCAL_DIR)) { HiveConf conf = SessionState.get().getConf(); - String scratchDirPath = conf.getVar(HiveConf.ConfVars.SCRATCHDIR); - if (!scratchDirPath.endsWith(File.pathSeparator)) { - scratchDirPath = scratchDirPath + File.pathSeparator; - } - if (writeEntity.getLocation().getPath().startsWith(scratchDirPath)) { + String warehouseDir = conf.getVar(ConfVars.METASTOREWAREHOUSE); + URI scratchURI = new URI(PathUtils.parseDFSURI(warehouseDir, + conf.getVar(HiveConf.ConfVars.SCRATCHDIR))); + URI requestURI = new URI(PathUtils.parseDFSURI(warehouseDir, + writeEntity.getLocation().getPath())); + if (PathUtils.impliesURI(scratchURI, requestURI)) { return true; } - - String localScratchDirPath = conf.getVar(HiveConf.ConfVars.LOCALSCRATCHDIR); - if (!scratchDirPath.endsWith(File.pathSeparator)) { - localScratchDirPath = localScratchDirPath + File.pathSeparator; - } - if (writeEntity.getLocation().getPath().startsWith(localScratchDirPath)) { + URI localScratchURI = new URI(PathUtils.parseLocalURI(conf.getVar(HiveConf.ConfVars.LOCALSCRATCHDIR))); + URI localRequestURI = new URI(PathUtils.parseLocalURI(writeEntity.getLocation().getPath())); + if (PathUtils.impliesURI(localScratchURI, localRequestURI)) { return true; } } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-core/sentry-core-common/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/pom.xml b/sentry-core/sentry-core-common/pom.xml index 9b7d067..a14f129 100644 --- a/sentry-core/sentry-core-common/pom.xml +++ b/sentry-core/sentry-core-common/pom.xml @@ -27,4 +27,16 @@ limitations under the License. <artifactId>sentry-core-common</artifactId> <name>Sentry Core Common</name> + <dependencies> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + </project> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java new file mode 100644 index 0000000..1659450 --- /dev/null +++ b/sentry-core/sentry-core-common/src/main/java/org/apache/sentry/core/common/utils/PathUtils.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.core.common.utils; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; + +import com.google.common.base.Strings; + +public class PathUtils { + /** + * URI is a a special case. For URI's, /a implies /a/b. + * Therefore the test is "/a/b".startsWith("/a"); + */ + public static boolean impliesURI(URI privilegeURI, URI requestURI) + throws URISyntaxException { + if (privilegeURI.getPath() == null || requestURI.getPath() == null) { + return false; + } + // ensure that either both schemes are null or equal + if (privilegeURI.getScheme() == null) { + if (requestURI.getScheme() != null) { + return false; + } + } else if (!privilegeURI.getScheme().equals(requestURI.getScheme())) { + return false; + } + // request path does not contain relative parts /a/../b && + // request path starts with privilege path && + // authorities (nullable) are equal + String requestPath = ensureEndsWithSeparator(requestURI.getPath()); + String privilegePath = ensureEndsWithSeparator(privilegeURI.getPath()); + if (requestURI.getPath().equals(requestURI.normalize().getPath()) && + requestPath.startsWith(privilegePath) && + Strings.nullToEmpty(privilegeURI.getAuthority()).equals(Strings.nullToEmpty(requestURI.getAuthority()))) { + return true; + } + return false; + } + + /** + * The URI must be a directory as opposed to a partial + * path entry name. To ensure this is true we add a / + * at the end of the path. Without this the admin might + * grant access to /dir1 but the user would be given access + * to /dir1* whereas the admin meant /dir1/ + */ + private static String ensureEndsWithSeparator(String path) { + if (path.endsWith(File.separator)) { + return path; + } + return path + File.separator; + } + + public static String parseDFSURI(String warehouseDir, String uri) + throws URISyntaxException { + return parseDFSURI(warehouseDir, uri, false); + } + + /** + * Parse a URI which should be on HDFS in the normal case but can be on a local + * file system in the testing case. In either case it should be on the same fs + * as the warehouse directory. + */ + public static String parseDFSURI(String warehouseDir, String uri, boolean isLocal) + throws URISyntaxException { + if ((uri.startsWith("file://") || uri.startsWith("hdfs://"))) { + return uri; + } else { + if (uri.startsWith("file:")) { + uri = uri.replace("file:", "file://"); + } else if (uri.startsWith("/")) { + if (warehouseDir.startsWith("hdfs:")) { + URI warehouse = toDFSURI(warehouseDir); + uri = warehouse.getScheme() + "://" + warehouse.getAuthority() + uri; + } else if (warehouseDir.startsWith("file:")) { + uri = "file://" + uri; + } else { + if (isLocal) { + uri = "file://" + uri; + } else { + // TODO fix this logic. I don't see why we would want to add hdfs:// + // to a URI at this point in time since no namenode is specified + // and warehouseDir appear to just be a path starting with / ? + // I think in the isLocal = false case we might want to throw + uri = "hdfs://" + uri; + } + } + } + return uri; + } + } + + /** + * Parse a URI which is on a local file system. + */ + public static String parseLocalURI(String uri) + throws URISyntaxException { + if (uri.startsWith("file://")) { + return uri; + } else if (uri.startsWith("file:")) { + return uri.replace("file:", "file://"); + } else if (uri.startsWith("/")) { + return "file://" + uri; + } + throw new IllegalStateException("Parse URI does not work on relative URI: " + uri); + } + + private static URI toDFSURI(String s) throws URISyntaxException { + URI uri = new URI(s); + if(uri.getScheme() == null || uri.getAuthority() == null) { + throw new IllegalArgumentException("Invalid URI " + s + ". No scheme or authority."); + } + return uri; + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java ---------------------------------------------------------------------- diff --git a/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java b/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java new file mode 100644 index 0000000..28818ba --- /dev/null +++ b/sentry-core/sentry-core-common/src/test/java/org/apache/sentry/core/common/utils/TestPathUtils.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sentry.core.common.utils; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import java.net.URI; +import org.junit.Test; + +public class TestPathUtils { + + @Test + public void testNullScheme() throws Exception { + assertTrue(PathUtils.impliesURI(new URI("/tmp"), new URI("/tmp/a"))); + assertFalse(PathUtils.impliesURI(new URI("file:/tmp"), new URI("/tmp/a"))); + assertFalse(PathUtils.impliesURI(new URI("/tmp"), new URI("file:/tmp/a"))); + // Privileges on /tmp/ are distinct from /tmp.+/ e.g. /tmp/ and /tmpdata/ + assertFalse(PathUtils.impliesURI(new URI("/tmp"), new URI("/tmpdata"))); + } + + @Test + public void testParseDFSURI() throws Exception { + // warehouse hdfs, path / + assertEquals("hdfs://namenode:8020/tmp/hive-user", PathUtils. + parseDFSURI("hdfs://namenode:8020/user/hive/warehouse", "/tmp/hive-user")); + // warehouse hdfs, path hdfs + assertEquals("hdfs://namenode:8020/tmp/hive-user", PathUtils. + parseDFSURI("hdfs://namenode:8020/user/hive/warehouse", "hdfs://namenode:8020/tmp/hive-user")); + + // warehouse file:///, path / + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:///tmp/hive-warehouse", "/tmp/hive-user")); + // warehouse file:///, path file:/ + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:///tmp/hive-warehouse", "file:/tmp/hive-user")); + // warehouse file:///, path file:/// + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:///tmp/hive-warehouse", "file:///tmp/hive-user")); + + // warehouse file:/, path / + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:/tmp/hive-warehouse", "/tmp/hive-user")); + // warehouse file:/, path file:/ + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:/tmp/hive-warehouse", "file:/tmp/hive-user")); + // warehouse file:/, path file:/// + assertEquals("file:///tmp/hive-user", PathUtils. + parseDFSURI("file:/tmp/hive-warehouse", "file:///tmp/hive-user")); + } + + @Test + public void testParseLocalURI() throws Exception { + assertEquals("file:///tmp/hive-user", PathUtils. + parseLocalURI("/tmp/hive-user")); + assertEquals("file:///tmp/hive-user", PathUtils. + parseLocalURI("file:/tmp/hive-user")); + assertEquals("file:///tmp/hive-user", PathUtils. + parseLocalURI("file:///tmp/hive-user")); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java ---------------------------------------------------------------------- diff --git a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java index e0eb2dc..01981d1 100644 --- a/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java +++ b/sentry-policy/sentry-policy-db/src/main/java/org/apache/sentry/policy/db/DBWildcardPermission.java @@ -24,13 +24,13 @@ package org.apache.sentry.policy.db; import static org.apache.sentry.provider.file.PolicyFileConstants.AUTHORIZABLE_JOINER; import static org.apache.sentry.provider.file.PolicyFileConstants.AUTHORIZABLE_SPLITTER; -import java.io.File; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import org.apache.commons.lang.text.StrSubstitutor; +import org.apache.sentry.core.common.utils.PathUtils; import org.apache.sentry.core.model.db.AccessConstants; import org.apache.sentry.core.model.db.DBModelAuthorizable.AuthorizableType; import org.apache.sentry.policy.common.PermissionFactory; @@ -133,56 +133,26 @@ public class DBWildcardPermission implements Permission, Serializable { return false; } - /** - * URI is a a special case. For URI's, /a implies /a/b. - * Therefore the test is "/a/b".startsWith("/a"); - */ @VisibleForTesting - protected static boolean impliesURI(String policy, String request) { + protected static boolean impliesURI(String privilege, String request) { try { - URI policyURI = new URI(new StrSubstitutor(System.getProperties()).replace(policy)); - URI requestURI = new URI(request); - if(policyURI.getScheme() == null || policyURI.getPath() == null) { - LOGGER.warn("Policy URI " + policy + " is not valid. Either no scheme or no path."); - return false; - } - if(requestURI.getScheme() == null || requestURI.getPath() == null) { - LOGGER.warn("Request URI " + request + " is not valid. Either no scheme or no path."); - return false; - } - // schemes are equal && - // request path does not contain relative parts /a/../b && - // request path starts with policy path && - // authorities (nullable) are equal - String requestPath = ensureEndsWithSeparator(requestURI.getPath()); - String policyPath = ensureEndsWithSeparator(policyURI.getPath()); - if(policyURI.getScheme().equals(requestURI.getScheme()) && - requestURI.getPath().equals(new URI(request).normalize().getPath()) && - requestPath.startsWith(policyPath) && - Strings.nullToEmpty(policyURI.getAuthority()).equals(Strings.nullToEmpty(requestURI.getAuthority()))) { - return true; - } + URI privilegeURI = new URI(new StrSubstitutor(System.getProperties()).replace(privilege)); + URI requestURI = new URI(request); + if(privilegeURI.getScheme() == null || privilegeURI.getPath() == null) { + LOGGER.warn("Privilege URI " + request + " is not valid. Either no scheme or no path."); return false; + } + if(requestURI.getScheme() == null || requestURI.getPath() == null) { + LOGGER.warn("Request URI " + request + " is not valid. Either no scheme or no path."); + return false; + } + return PathUtils.impliesURI(privilegeURI, requestURI); } catch (URISyntaxException e) { LOGGER.warn("Request URI " + request + " is not a URI", e); return false; } } - /** - * The URI must be a directory as opposed to a partial - * path entry name. To ensure this is true we add a / - * at the end of the path. Without this the admin might - * grant access to /dir1 but the user would be given access - * to /dir1* whereas the admin meant /dir1/ - */ - private static String ensureEndsWithSeparator(String path) { - if (path.endsWith(File.separator)) { - return path; - } - return path + File.separator; - } - @Override public String toString() { return AUTHORIZABLE_JOINER.join(parts); http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-provider/sentry-provider-file/pom.xml ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-file/pom.xml b/sentry-provider/sentry-provider-file/pom.xml index a804952..60c4836 100644 --- a/sentry-provider/sentry-provider-file/pom.xml +++ b/sentry-provider/sentry-provider-file/pom.xml @@ -29,6 +29,10 @@ limitations under the License. <dependencies> <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + </dependency> + <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/a9f9790b/sentry-tests/sentry-tests-hive/.gitignore ---------------------------------------------------------------------- diff --git a/sentry-tests/sentry-tests-hive/.gitignore b/sentry-tests/sentry-tests-hive/.gitignore new file mode 100644 index 0000000..f8feb49 --- /dev/null +++ b/sentry-tests/sentry-tests-hive/.gitignore @@ -0,0 +1,2 @@ +derby.log +TempStatsStore/**
